import { type Dashboard, type DataSourceRef } from '@grafana/schema';
import { type ObjectMeta } from 'app/features/apiserver/types';
import { type DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { type ProvisioningPreview } from 'app/features/provisioning/types';

export interface HomeDashboardRedirectDTO {
  redirectUri: string;
}

export interface DashboardDTO {
  dashboard: DashboardDataDTO;
  meta: DashboardMeta;
}

export interface SaveDashboardResponseDTO {
  slug: string;
  status: string;
  uid: string;
  url: string;
  version: number;
}

export interface DashboardMeta {
  slug?: string;
  uid?: string;
  canSave?: boolean;
  canEdit?: boolean;
  canDelete?: boolean;
  canShare?: boolean;
  canStar?: boolean;
  canAdmin?: boolean;
  url?: string;
  folderUid?: string;
  canMakeEditable?: boolean;
  provisioned?: boolean;
  provisionedExternalId?: string;
  showSettings?: boolean;
  expires?: string;
  isFolder?: boolean;
  isSnapshot?: boolean;
  snapshotKey?: string;
  folderTitle?: string;
  folderUrl?: string;
  folderId?: number;
  created?: string;
  createdBy?: string;
  updated?: string;
  updatedBy?: string;
  fromScript?: boolean;
  fromFile?: boolean;
  hasUnsavedFolderChange?: boolean;
  annotationsPermissions?: AnnotationsPermissions;
  publicDashboardEnabled?: boolean;
  isEmbedded?: boolean;
  isNew?: boolean;
  version?: number;

  // Dashboard template edit flow. Set when a dashboard scene was hydrated from an DashboardTemplate
  // via DashboardRoutes.Template with editTemplate=true.
  isDashboardTemplate?: boolean;
  dashboardTemplateUid?: string;

  // When loaded from kubernetes, we stick the raw metadata here
  // yes weird, but this means all the editor structures can exist unchanged
  // until we use the resource as the main container
  k8s?: Partial<ObjectMeta>;

  // If the dashboard was loaded from a remote repository
  provisioning?: ProvisioningPreview;

  // This is a property added specifically for edge cases where dashboards should be reloaded on scopes, time range or variables changes
  // This property is not persisted in the DB but its existence is controlled by the API
  reloadOnParamsChange?: boolean;

  // Conversion status from the API response, indicating if the dashboard was converted from another version
  conversionStatus?: {
    storedVersion?: string;
    failed: boolean;
    error?: string;
  };
}

interface AnnotationActions {
  canAdd: boolean;
  canEdit: boolean;
  canDelete: boolean;
}

export interface AnnotationsPermissions {
  dashboard: AnnotationActions;
}

// FIXME: This should not override Dashboard types
export interface DashboardDataDTO extends Dashboard {
  title: string;
  uid: string;
  panels?: any[];
}

export enum DashboardRoutes {
  Home = 'home-dashboard',
  New = 'new-dashboard',
  Template = 'template-dashboard',
  Normal = 'normal-dashboard',
  Provisioning = 'provisioning-dashboard',
  Scripted = 'scripted-dashboard',
  Public = 'public-dashboard',
  Embedded = 'embedded-dashboard',
  Report = 'report-dashboard',
  AssistantPreview = 'assistant-preview',
}

export enum DashboardInitPhase {
  NotStarted = 'Not started',
  Fetching = 'Fetching',
  Services = 'Services',
  Failed = 'Failed',
  Completed = 'Completed',
}

export interface DashboardInitError {
  message: string;
  error: unknown;
}

export enum KioskMode {
  Full = 'full',
}

type GetMutableDashboardModelFn = () => DashboardModel | null;

export interface DashboardState {
  getModel: GetMutableDashboardModelFn;
  initPhase: DashboardInitPhase;
  initialDatasource?: DataSourceRef['uid'];
  initError: DashboardInitError | null;
}

export const DASHBOARD_FROM_LS_KEY = 'DASHBOARD_FROM_LS_KEY';

export function isRedirectResponse<T extends object>(
  dto: T | HomeDashboardRedirectDTO
): dto is HomeDashboardRedirectDTO {
  return 'redirectUri' in dto;
}
