import { apiClient } from "./client";

export interface Outline {
  id: string;
  projectId: string;
  title: string;
  genre: string;
  episodeCount: number;
  synopsis: string;
  status: string;
  createdAt: string;
}

export interface Episode {
  id: string;
  outlineId: string;
  episodeNumber: number;
  title: string;
  summary: string;
  script: string;
  status: string;
  storyboardCount: number;
  createdAt: string;
}

export interface Storyboard {
  id: string;
  episodeId: string;
  sequenceNum: number;
  sceneNumber: string;
  shortDescription: string;
  detailedDescription: string;
  characters: string;
  sceneRef?: string | null;
  videoPrompt?: string | null;
  dialogues: string;
  cameraDirection: string;
  compositionGuide: string;
  durationSeconds: number;
  startFramePrompt: string;
  motionScript: string;
  notes: string;
  status: string;
  createdAt: string;
  updatedAt: string;
  characterImageKeys?: string[] | null;
  sceneImageKey?: string | null;
  propImageKeys?: string[] | null;
  styleImageKey?: string | null;
  firstFrameImageKey?: string | null;
  firstFrameImageUrl?: string | null;
  lastFrameImageKey?: string | null;
  lastFrameImageUrl?: string | null;
}

export interface ShotAsset {
  id: string;
  storyboardId: string;
  projectId: string | null;
  episodeId: string | null;
  assetType: "first_frame" | "last_frame" | "reference" | "video" | string;
  tosKey: string | null;
  externalUrl: string | null;
  sourceTaskId: string | null;
  prompt: string | null;
  modelProvider: string | null;
  modelId: string | null;
  assetVersion: number;
  characters: string | null;
  metaJson: string | null;
  errorMessage: string | null;
  status: string;
  isActive: number;
  createdAt: string;
  updatedAt: string;
}

export interface Character {
  id: string;
  projectId: string;
  name: string;
  roleType: string;
  gender: string;
  age: string;
  personality: string;
  costume: string;
  visualHint: string;
  imagePrompt: string;
  imageUrl: string | null;
  imageTosKey: string | null;
  frontImageUrl?: string | null;
  frontImageTosKey?: string | null;
  sideImageUrl?: string | null;
  sideImageTosKey?: string | null;
  backImageUrl?: string | null;
  backImageTosKey?: string | null;
  status: string;
  createdAt: string;
}

export interface CharacterState {
  id: string;
  projectId: string;
  characterId: string;
  characterName?: string | null;
  name: string;
  stateType: string;
  description: string | null;
  prompt: string | null;
  referenceImageKey: string | null;
  imageUrl: string | null;
  imageTosKey: string | null;
  status: string;
  createdAt: string;
}

export interface Scene {
  id: string;
  projectId: string;
  name: string;
  sceneType: string;
  description: string;
  imagePrompt: string;
  imageUrl: string | null;
  imageTosKey: string | null;
  status: string;
  createdAt: string;
}

export interface AiTask {
  id: string;
  projectId: string;
  episodeId: string | null;
  storyboardId: string | null;
  taskType: string;
  status: string;
  resultVideoUrl: string | null;
  errorMessage: string | null;
  createdAt: string;
  updatedAt: string;
  // 结构化视频任务字段（task_type=structured_video 时非空）
  prompt?: string | null;
  characterImageKey?: string | null;
  characterImageKeys?: string[] | null;
  sceneImageKey?: string | null;
  propImageKeys?: string[] | null;
  styleImageKey?: string | null;
  userPrompt?: Record<string, string> | null;
  videoDuration?: number | null;
  videoRatio?: string | null;
  generateAudio?: boolean | null;
}

export interface StructuredVideoRequest {
  episodeId?: string | null;
  storyboardId?: string | null;
  /** 旧版单角色字段（characterImageKeys 非空时可省略） */
  characterImageKey?: string | null;
  /** V16：多角色出镜（@图1..@图N，按顺序） */
  characterImageKeys?: string[] | null;
  sceneImageKey?: string | null;
  propImageKeys?: string[] | null;
  styleImageKey?: string | null;
  firstFrameImageKey?: string | null;
  lastFrameImageKey?: string | null;
  /** V17：单段 freeform 提示词（与 userPrompt 二选一，优先使用） */
  freeformPrompt?: string | null;
  userPrompt?: {
    characterAction?: string | null;
    sceneEvent?: string | null;
    cameraMovement?: string | null;
    lightingAtmosphere?: string | null;
    videoStyle?: string | null;
  } | null;
  duration?: number | null;
  ratio?: string | null;
  generateAudio?: boolean | null;
}

export interface AssemblyTask {
  id: string;
  episodeId: string;
  status: string;
  shotCount: number;
  downloadUrl: string | null;
  errorMessage: string | null;
  createdAt: string;
  updatedAt: string;
}

export const aiApi = {
  // ---- Outline ----
  generateOutline: async (projectId: string, script: string): Promise<Outline> => {
    const r = await apiClient.post(`/projects/${projectId}/outline/generate`, { script });
    return r.data.data;
  },
  getOutline: async (projectId: string): Promise<Outline> => {
    const r = await apiClient.get(`/projects/${projectId}/outline`);
    return r.data.data;
  },
  updateOutline: async (projectId: string, patch: Partial<Outline>): Promise<Outline> => {
    const r = await apiClient.put(`/projects/${projectId}/outline`, patch);
    return r.data.data;
  },

  // ---- Episodes ----
  generateEpisodes: async (projectId: string): Promise<Episode[]> => {
    const r = await apiClient.post(`/projects/${projectId}/episodes/generate`);
    return r.data.data;
  },
  listEpisodes: async (projectId: string): Promise<Episode[]> => {
    const r = await apiClient.get(`/projects/${projectId}/episodes`);
    return r.data.data;
  },
  createEpisode: async (projectId: string, req: Partial<Episode>): Promise<Episode> => {
    const r = await apiClient.post(`/projects/${projectId}/episodes`, req);
    return r.data.data;
  },
  updateEpisode: async (projectId: string, episodeId: string, patch: Partial<Episode>): Promise<Episode> => {
    const r = await apiClient.put(`/projects/${projectId}/episodes/${episodeId}`, patch);
    return r.data.data;
  },

  // ---- Storyboards ----
  createStoryboard: async (projectId: string, episodeId: string, req: Partial<Storyboard>): Promise<Storyboard> => {
    const r = await apiClient.post(`/projects/${projectId}/episodes/${episodeId}/storyboards`, req);
    return r.data.data;
  },
  generateStoryboards: async (projectId: string, episodeId: string): Promise<Storyboard[]> => {
    const r = await apiClient.post(`/projects/${projectId}/episodes/${episodeId}/storyboards/generate`);
    return r.data.data;
  },
  listStoryboards: async (projectId: string, episodeId: string): Promise<Storyboard[]> => {
    const r = await apiClient.get(`/projects/${projectId}/episodes/${episodeId}/storyboards`);
    return r.data.data;
  },
  updateStoryboard: async (projectId: string, storyboardId: string, patch: Partial<Storyboard>): Promise<Storyboard> => {
    const r = await apiClient.put(`/projects/${projectId}/storyboards/${storyboardId}`, patch);
    return r.data.data;
  },
  uploadStoryboardFrameImage: async (
    projectId: string,
    storyboardId: string,
    frameType: "first" | "last",
    file: File
  ): Promise<Storyboard> => {
    const form = new FormData();
    form.append("file", file);
    const r = await apiClient.post(
      `/projects/${projectId}/storyboards/${storyboardId}/frame-image?frameType=${frameType}`,
      form,
      { headers: { "Content-Type": "multipart/form-data" }, timeout: 600_000 }
    );
    return r.data.data;
  },
  deleteStoryboard: async (projectId: string, storyboardId: string): Promise<void> => {
    await apiClient.delete(`/projects/${projectId}/storyboards/${storyboardId}`);
  },
  reorderStoryboards: async (projectId: string, ids: string[]): Promise<void> => {
    await apiClient.put(`/projects/${projectId}/storyboards/reorder`, { ids });
  },
  generateStoryboardPrompt: async (projectId: string, storyboardId: string): Promise<string> => {
    const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/generate-prompt`);
    return r.data.data.prompt;
  },
  listShotAssets: async (projectId: string, storyboardId: string): Promise<ShotAsset[]> => {
    const r = await apiClient.get(`/projects/${projectId}/storyboards/${storyboardId}/assets`);
    return r.data.data;
  },
  activateShotAsset: async (projectId: string, storyboardId: string, assetId: string): Promise<ShotAsset> => {
    const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/assets/${assetId}/activate`);
    return r.data.data;
  },

  // ---- Characters ----
  extractCharacters: async (projectId: string): Promise<Character[]> => {
    const r = await apiClient.post(
      `/projects/${projectId}/characters/extract`,
      undefined,
      { timeout: 180_000 }
    );
    return r.data.data;
  },
  listCharacters: async (projectId: string): Promise<Character[]> => {
    const r = await apiClient.get(`/projects/${projectId}/characters`);
    return r.data.data;
  },
  listAllCharacterStates: async (projectId: string): Promise<CharacterState[]> => {
    const r = await apiClient.get(`/projects/${projectId}/characters/states`);
    return r.data.data;
  },
  listCharacterStates: async (projectId: string, characterId: string): Promise<CharacterState[]> => {
    const r = await apiClient.get(`/projects/${projectId}/characters/${characterId}/states`);
    return r.data.data;
  },
  saveCharacter: async (projectId: string, req: Partial<Character>): Promise<Character> => {
    const r = await apiClient.post(`/projects/${projectId}/characters`, req);
    return r.data.data;
  },
  saveCharacterState: async (
    projectId: string,
    characterId: string,
    req: Partial<CharacterState>
  ): Promise<CharacterState> => {
    const r = await apiClient.post(`/projects/${projectId}/characters/${characterId}/states`, req);
    return r.data.data;
  },
  generateCharacterImage: async (projectId: string, characterId: string): Promise<Character> => {
    const r = await apiClient.post(
      `/projects/${projectId}/characters/${characterId}/generate-image`,
      undefined,
      { timeout: 180_000 }
    );
    return r.data.data;
  },
  generateCharacterStateImage: async (
    projectId: string,
    characterId: string,
    stateId: string
  ): Promise<CharacterState> => {
    const r = await apiClient.post(
      `/projects/${projectId}/characters/${characterId}/states/${stateId}/generate-image`,
      undefined,
      { timeout: 180_000 }
    );
    return r.data.data;
  },
  uploadCharacterImage: async (
    projectId: string,
    characterId: string,
    file: File,
    viewType: "front" | "side" | "back" = "front"
  ): Promise<Character> => {
    const form = new FormData();
    form.append("file", file);
    const r = await apiClient.post(
      `/projects/${projectId}/characters/${characterId}/upload-image?viewType=${viewType}`,
      form,
      { headers: { "Content-Type": "multipart/form-data" } }
    );
    return r.data.data;
  },
  deleteCharacter: async (projectId: string, characterId: string): Promise<void> => {
    await apiClient.delete(`/projects/${projectId}/characters/${characterId}`);
  },
  deleteCharacterState: async (projectId: string, characterId: string, stateId: string): Promise<void> => {
    await apiClient.delete(`/projects/${projectId}/characters/${characterId}/states/${stateId}`);
  },

  // ---- Scenes ----
  extractScenes: async (projectId: string): Promise<Scene[]> => {
    const r = await apiClient.post(
      `/projects/${projectId}/scenes/extract`,
      undefined,
      { timeout: 180_000 }
    );
    return r.data.data;
  },
  listScenes: async (projectId: string): Promise<Scene[]> => {
    const r = await apiClient.get(`/projects/${projectId}/scenes`);
    return r.data.data;
  },
  saveScene: async (projectId: string, req: Partial<Scene>): Promise<Scene> => {
    const r = await apiClient.post(`/projects/${projectId}/scenes`, req);
    return r.data.data;
  },
  generateSceneImage: async (projectId: string, sceneId: string): Promise<Scene> => {
    const r = await apiClient.post(
      `/projects/${projectId}/scenes/${sceneId}/generate-image`,
      undefined,
      { timeout: 120_000 }
    );
    return r.data.data;
  },
  uploadSceneImage: async (projectId: string, sceneId: string, file: File): Promise<Scene> => {
    const form = new FormData();
    form.append("file", file);
    const r = await apiClient.post(`/projects/${projectId}/scenes/${sceneId}/upload-image`, form, { headers: { "Content-Type": "multipart/form-data" } });
    return r.data.data;
  },
  deleteScene: async (projectId: string, sceneId: number | string): Promise<void> => {
    await apiClient.delete(`/projects/${projectId}/scenes/${sceneId}`);
  },

  // ---- Video Tasks ----
  generateVideo: async (
    projectId: string,
    episodeId: string | null,
    prompt: string,
    videoPrompt?: string,
    storyboardId?: string | null,
    imageKeys?: string[] | null,
    duration?: number
  ): Promise<AiTask> => {
    const r = await apiClient.post(`/projects/${projectId}/video-tasks/generate`, {
      episode_id: episodeId ?? undefined,
      storyboard_id: storyboardId ?? undefined,
      prompt,
      video_prompt: videoPrompt ?? prompt,
      ...(imageKeys && imageKeys.length > 0 ? { image_keys: imageKeys } : {}),
      ...(duration ? { duration } : {}),
    });
    return r.data.data;
  },
  generateStructuredVideo: async (
    projectId: string,
    req: StructuredVideoRequest
  ): Promise<AiTask> => {
    const r = await apiClient.post(
      `/projects/${projectId}/video-tasks/generate-structured`,
      req
    );
    return r.data.data;
  },
  deleteVideoTask: async (projectId: string, taskId: string): Promise<void> => {
    await apiClient.delete(`/projects/${projectId}/video-tasks/${taskId}`);
  },
  pollVideoTask: async (projectId: string, taskId: string): Promise<AiTask> => {
    const r = await apiClient.get(`/projects/${projectId}/video-tasks/${taskId}`);
    return r.data.data;
  },
  listVideoTasks: async (projectId: string): Promise<AiTask[]> => {
    const r = await apiClient.get(`/projects/${projectId}/video-tasks`);
    return r.data.data;
  },

  // ---- Assembly ----
  startAssembly: async (projectId: string, episodeId: string, videoTaskIds?: string[]): Promise<AssemblyTask> => {
    const r = await apiClient.post(`/projects/${projectId}/episodes/${episodeId}/assembly`, {
      videoTaskIds,
    });
    return r.data.data;
  },
  getAssemblyTask: async (projectId: string, episodeId: string): Promise<AssemblyTask | null> => {
    const r = await apiClient.get(`/projects/${projectId}/episodes/${episodeId}/assembly`);
    return r.data.data ?? null;
  },
};
