import { Type, type Static } from "@sinclair/typebox";

import { GenerationErrorCategorySchema } from "./api.js";
import { CanvasStateSchema } from "./canvas.js";

const uuidPattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
const isoTimestampPattern = "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$";

export const ProjectIdSchema = Type.String({ pattern: uuidPattern, $id: "ProjectId" });
export const ProjectRatioSchema = Type.Union(
  [Type.Literal("3:4"), Type.Literal("1:1"), Type.Literal("4:3"), Type.Literal("9:16")],
  { $id: "ProjectRatio" },
);
export const ProjectViewStatusSchema = Type.Union(
  [Type.Literal("active"), Type.Literal("failed_empty"), Type.Literal("trashed")],
  { $id: "ProjectViewStatus" },
);
export const ProjectSummarySchema = Type.Object(
  {
    current_image_id: Type.Union([Type.Ref(ProjectIdSchema), Type.Null()]),
    deleted_at: Type.Union([Type.String({ pattern: isoTimestampPattern }), Type.Null()]),
    name: Type.String({ maxLength: 160, minLength: 1 }),
    project_id: Type.Ref(ProjectIdSchema),
    purge_at: Type.Union([Type.String({ pattern: isoTimestampPattern }), Type.Null()]),
    ratio: Type.Ref(ProjectRatioSchema),
    state_version: Type.Integer({ minimum: 1 }),
    status: Type.Ref(ProjectViewStatusSchema),
    successful_image_count: Type.Integer({ maximum: 10, minimum: 0 }),
    updated_at: Type.String({ pattern: isoTimestampPattern }),
  },
  { additionalProperties: false, $id: "ProjectSummary" },
);
export const ProjectListQuerySchema = Type.Object(
  { status: Type.Optional(Type.Union([Type.Literal("active"), Type.Literal("trashed")])) },
  { additionalProperties: false, $id: "ProjectListQuery" },
);
export const ProjectListResponseSchema = Type.Object(
  {
    active_count: Type.Integer({ maximum: 20, minimum: 0 }),
    active_limit: Type.Literal(20),
    projects: Type.Array(Type.Ref(ProjectSummarySchema), { maxItems: 20 }),
  },
  { additionalProperties: false, $id: "ProjectListResponse" },
);
export const ProjectParamsSchema = Type.Object(
  { projectId: Type.Ref(ProjectIdSchema) },
  { additionalProperties: false, $id: "ProjectParams" },
);
export const GenerationProjectItemSchema = Type.Object(
  {
    created_at: Type.String({ pattern: isoTimestampPattern }),
    error_category: Type.Union([Type.Ref(GenerationErrorCategorySchema), Type.Null()]),
    generation_id: Type.String({ pattern: uuidPattern }),
    prompt: Type.String({ maxLength: 4_000, minLength: 1 }),
    ratio: Type.Ref(ProjectRatioSchema),
    status: Type.Union([
      Type.Literal("queued"), Type.Literal("running"), Type.Literal("succeeded"),
      Type.Literal("failed"), Type.Literal("rejected"),
    ]),
    updated_at: Type.String({ pattern: isoTimestampPattern }),
  },
  { additionalProperties: false, $id: "GenerationProjectItem" },
);
export const ProjectImageItemSchema = Type.Object(
  {
    created_at: Type.String({ pattern: isoTimestampPattern }),
    generation_id: Type.String({ pattern: uuidPattern }),
    image_id: Type.Ref(ProjectIdSchema),
  },
  { additionalProperties: false, $id: "ProjectImageItem" },
);
export const ExportFormatSchema = Type.Union([Type.Literal("jpg"), Type.Literal("png")], { $id: "ExportFormat" });
export const LatestExportItemSchema = Type.Object(
  {
    byte_size: Type.Integer({ minimum: 1 }),
    created_at: Type.String({ pattern: isoTimestampPattern }),
    download_url: Type.String({ pattern: "^/api/v1/projects/[0-9a-fA-F-]{36}/latest-exports/(jpg|png)$" }),
    export_id: Type.String({ pattern: uuidPattern }),
    format: Type.Ref(ExportFormatSchema),
    pixel_height: Type.Integer({ minimum: 1 }),
    pixel_width: Type.Integer({ minimum: 1 }),
    sha256: Type.String({ pattern: "^[0-9a-f]{64}$" }),
    state_version: Type.Integer({ minimum: 1 }),
  },
  { additionalProperties: false, $id: "LatestExportItem" },
);
export const ProjectDetailResponseSchema = Type.Object(
  {
    ...ProjectSummarySchema.properties,
    canvas_state: Type.Ref(CanvasStateSchema),
    created_at: Type.String({ pattern: isoTimestampPattern }),
    draft_prompt: Type.String({ maxLength: 4_000, minLength: 1 }),
    generations: Type.Array(Type.Ref(GenerationProjectItemSchema)),
    images: Type.Array(Type.Ref(ProjectImageItemSchema), { maxItems: 10 }),
    latest_exports: Type.Array(Type.Ref(LatestExportItemSchema), { maxItems: 2 }),
    pixel_height: Type.Integer({ minimum: 1 }),
    pixel_width: Type.Integer({ minimum: 1 }),
    save_status: Type.Literal("saved"),
  },
  { additionalProperties: false, $id: "ProjectDetailResponse" },
);
export const LatestExportParamsSchema = Type.Object(
  { format: Type.Ref(ExportFormatSchema), projectId: Type.Ref(ProjectIdSchema) },
  { additionalProperties: false, $id: "LatestExportParams" },
);
export const ProjectImageParamsSchema = Type.Object(
  { imageId: Type.Ref(ProjectIdSchema), projectId: Type.Ref(ProjectIdSchema) },
  { additionalProperties: false, $id: "ProjectImageParams" },
);
export const LatestExportMultipartBodySchema = Type.Object(
  {
    byte_size: Type.String({ pattern: "^[1-9][0-9]*$" }),
    export_file: Type.String({ format: "binary" }),
    export_id: Type.String({ pattern: uuidPattern }),
    format: Type.Ref(ExportFormatSchema),
    pixel_height: Type.String({ pattern: "^[1-9][0-9]*$" }),
    pixel_width: Type.String({ pattern: "^[1-9][0-9]*$" }),
    sha256: Type.String({ pattern: "^[0-9a-f]{64}$" }),
    state_version: Type.String({ pattern: "^[1-9][0-9]*$" }),
  },
  { additionalProperties: false, $id: "LatestExportMultipartBody" },
);
export const LatestExportSaveResponseSchema = Type.Object(
  {
    ...LatestExportItemSchema.properties,
    status: Type.Literal("saved"),
  },
  { additionalProperties: false, $id: "LatestExportSaveResponse" },
);
export const ProjectRenameRequestSchema = Type.Object(
  { name: Type.String({ maxLength: 80, minLength: 1 }) },
  { additionalProperties: false, $id: "ProjectRenameRequest" },
);
export const ProjectRenameResponseSchema = Type.Object(
  {
    name: Type.String({ maxLength: 80, minLength: 1 }),
    state_version: Type.Integer({ minimum: 2 }),
    status: Type.Literal("renamed"),
  },
  { additionalProperties: false, $id: "ProjectRenameResponse" },
);
export const FailedEmptyTrashRequestSchema = Type.Object(
  { project_ids: Type.Array(Type.Ref(ProjectIdSchema), { maxItems: 20, minItems: 1, uniqueItems: true }) },
  { additionalProperties: false, $id: "FailedEmptyTrashRequest" },
);
export const FailedEmptyTrashResponseSchema = Type.Object(
  {
    ignored_project_ids: Type.Array(Type.Ref(ProjectIdSchema), { maxItems: 20, uniqueItems: true }),
    trashed_project_ids: Type.Array(Type.Ref(ProjectIdSchema), { maxItems: 20, uniqueItems: true }),
  },
  { additionalProperties: false, $id: "FailedEmptyTrashResponse" },
);
export const ProjectTrashResponseSchema = Type.Object(
  {
    deleted_at: Type.String({ pattern: isoTimestampPattern }),
    project_id: Type.Ref(ProjectIdSchema),
    purge_at: Type.String({ pattern: isoTimestampPattern }),
    status: Type.Literal("trashed"),
  },
  { additionalProperties: false, $id: "ProjectTrashResponse" },
);
export const ProjectRestoreResponseSchema = Type.Object(
  {
    deleted_at: Type.Null(),
    project_id: Type.Ref(ProjectIdSchema),
    purge_at: Type.Null(),
    status: Type.Literal("active"),
  },
  { additionalProperties: false, $id: "ProjectRestoreResponse" },
);
export const ProjectPurgeResponseSchema = Type.Object(
  {
    project_id: Type.Ref(ProjectIdSchema),
    status: Type.Literal("purged"),
  },
  { additionalProperties: false, $id: "ProjectPurgeResponse" },
);

export type ProjectListQuery = Static<typeof ProjectListQuerySchema>;
export type ProjectParams = Static<typeof ProjectParamsSchema>;
export type LatestExportParams = Static<typeof LatestExportParamsSchema>;
export type ProjectImageParams = Static<typeof ProjectImageParamsSchema>;
export type ProjectRenameRequest = Static<typeof ProjectRenameRequestSchema>;
export type FailedEmptyTrashRequest = Static<typeof FailedEmptyTrashRequestSchema>;
