import {
  defineVQTimeline,
  say,
  type VQCustomTimelineEvent,
  type VQSpeechEvent,
  type VQTimelineEvent,
  type VQTimelineInputEvent,
} from "../../lib/VQRemotionLib/timeline";
import type {VQMouthShape} from "../../lib/VQRemotionLib/types";
import type {CharacterId, VoicevoxVoice} from "./characters";

export {characters} from "./characters";
export type {CharacterDefinition, CharacterId, VoicevoxVoice} from "./characters";

export type ExpressionId =
  | "default"
  | "blink"
  | "confident"
  | "surprised"
  | "exasperated"
  | "roundEyes"
  | "roundEyesSmall"
  | "huh"
  | "tears"
  | "yabeAhe"
  | "nnaa"
  | "gesu";

export type DemoExpression = Readonly<{
  expressionId: ExpressionId;
  label: string;
  imagePath: string;
  durationSeconds: number;
}>;

export const demoExpressions = [
  {
    expressionId: "default",
    label: "default",
    imagePath: "image/zundamon-ohnegus-rework-baby/06-default-nniya.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "blink",
    label: "blink",
    imagePath: "image/zundamon-ohnegus-rework-baby/13-blink-nniya.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "confident",
    label: "confident",
    imagePath: "image/zundamon-ohnegus-rework-baby/20-confident-nniya.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "surprised",
    label: "surprised",
    imagePath: "image/zundamon-ohnegus-rework-baby/27-surprised-nniya.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "exasperated",
    label: "exasperated",
    imagePath: "image/zundamon-ohnegus-rework-baby/32-exasperated-nniya.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "roundEyes",
    label: "round-eyes",
    imagePath: "image/zundamon-ohnegus-rework-baby/35-round-eyes-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "roundEyesSmall",
    label: "round-eyes-small",
    imagePath: "image/zundamon-ohnegus-rework-baby/37-round-eyes-small-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "huh",
    label: "huh",
    imagePath: "image/zundamon-ohnegus-rework-baby/39-huh-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "tears",
    label: "tears",
    imagePath: "image/zundamon-ohnegus-rework-baby/41-tears-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "yabeAhe",
    label: "yabe-ahe",
    imagePath: "image/zundamon-ohnegus-rework-baby/43-yabe-ahe-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "nnaa",
    label: "nnaa",
    imagePath: "image/zundamon-ohnegus-rework-baby/45-nnaa-n.png",
    durationSeconds: 1.1,
  },
  {
    expressionId: "gesu",
    label: "gesu",
    imagePath: "image/zundamon-ohnegus-rework-baby/46-gesu.png",
    durationSeconds: 1.1,
  },
] as const satisfies readonly DemoExpression[];

export type SpeechEvent = VQSpeechEvent<CharacterId, VoicevoxVoice>;

export type ExpressionEvent = VQCustomTimelineEvent<
  "expression",
  DemoExpression & {id: string}
>;

export type MouthCycleEvent = VQCustomTimelineEvent<
  "mouthCycle",
  {
    id: string;
    label: string;
    durationSeconds: number;
    mouths: readonly VQMouthShape[];
  }
>;

export type TimelineEvent = VQTimelineEvent<
  CharacterId,
  VoicevoxVoice,
  ExpressionEvent | MouthCycleEvent
>;
export type TimelineInputEvent = VQTimelineInputEvent<
  CharacterId,
  VoicevoxVoice,
  ExpressionEvent | MouthCycleEvent
>;

// 用途: 表情確認用の静止フル画像イベントをタイムラインへ追加する。
// 使用方法: expression("id", demoExpressions[0]) のように呼び、描画側で imagePath を表示する。
// オプションや引数詳細: expressionData は表情ID、表示ラベル、public相対画像パス、表示秒数を含む。
export const expression = (
  id: string,
  expressionData: DemoExpression
): ExpressionEvent => ({
  type: "expression",
  id,
  expressionId: expressionData.expressionId,
  label: expressionData.label,
  imagePath: expressionData.imagePath,
  durationSeconds: expressionData.durationSeconds,
});

// 用途: Rhubarb生成結果に依存せず、全口形を明示表示する確認イベントを作る。
// 使用方法: mouthCycle("id") をタイムラインに置き、描画側で mouths を順番に切り替える。
// オプションや引数詳細: durationSeconds は全口形を一巡させる総秒数、mouths は表示順を指定する。
export const mouthCycle = (
  id: string,
  options: Partial<Pick<MouthCycleEvent, "durationSeconds" | "mouths">> = {}
): MouthCycleEvent => ({
  type: "mouthCycle",
  id,
  label: "rhubarb-mouths",
  durationSeconds: options.durationSeconds ?? 2.8,
  mouths: options.mouths ?? ["rest", "closed", "a", "i", "u", "e", "o"],
});

export const timeline = defineVQTimeline([
  say(
    "zundamon-rework-standee-demo-zunda-001",
    "zundamon",
    "あ、い、う、え、お。ぱ、ぴ、ぷ、ぺ、ぽ。ん、まんま、なのだ。",
    {
      subtitle:
        "default表情のリップシンク確認なのだ。\nあ、い、う、え、お。ぱ、ぴ、ぷ、ぺ、ぽ。",
    }
  ),
  mouthCycle("zundamon-rework-standee-demo-mouth-cycle-001"),
  ...demoExpressions.map((expressionData, index) =>
    expression(
      `zundamon-rework-standee-demo-expression-${String(index + 1).padStart(
        2,
        "0"
      )}`,
      expressionData
    )
  ),
] satisfies readonly TimelineInputEvent[]);
