import type { CanvasState } from "@dada/shared-contracts";
import { P0A_DYNAMIC_STICKER_IDS } from "@dada/template-registry";

import { DYNAMIC_RESOURCE_VERSION } from "./dynamic-render-models.js";
import type { CanvasElementIdentity } from "./editor-elements.js";

type CanvasElement = CanvasState["elements"][number];

export type DynamicCategory = "identity" | "location" | "other" | "time";
export type DynamicTemplateId = typeof P0A_DYNAMIC_STICKER_IDS[number];

export interface DynamicStickerDefinition {
  category: DynamicCategory;
  displayName: string;
  requiresLocationConsent: boolean;
  templateId: DynamicTemplateId;
}

export interface DynamicProviderContext {
  location?: { formattedValue: string; latitude?: number; longitude?: number };
  now: Date;
  profile: { creatorName: string; socialId: string };
}

// Declarative conversion of l_shijian7.prefab. The browser never executes the Android Prefab or Lua.
export const DYN012_RENDER_LAYOUT = {
  background: "transparent",
  divider: { color: "#FFFFFF", height: 42, width: 7, x: 0, y: 0 },
  hour: { color: "#FFFFFF", fontId: "FONT081", fontSize: 100, x: -60, y: 0 },
  meridiem: { color: "#FFFFFF", fontId: "FONT081", fontSize: 20, x: 94, y: -65 },
  minute: { color: "#FFFFFF", fontId: "FONT081", fontSize: 100, x: 60, y: 0 },
} as const;

export function dyn012DisplayParts(element: CanvasElement) {
  if (element.type !== "dynamic_sticker" || element.template_or_asset_id !== "DYN012") throw new Error("dyn012_element_required");
  const formatted = element.formatted_value?.match(/^(\d{1,2}):(\d{2})$/);
  const hour = formatted?.[1]?.padStart(2, "0") ?? String(element.dynamic_fields?.hour ?? "00").padStart(2, "0");
  const minute = formatted?.[2] ?? String(element.dynamic_fields?.minute ?? "00").padStart(2, "0");
  const hourNumber = Number(hour);
  const minuteNumber = Number(minute);
  return {
    hour,
    meridiem: hourNumber > 12 || (hourNumber === 12 && minuteNumber > 0) ? "PM" : "AM",
    minute,
  } as const;
}

const dynamicDefinitions: readonly DynamicStickerDefinition[] = [
  { category: "location", displayName: "地点标题", requiresLocationConsent: false, templateId: "DYN001" },
  { category: "location", displayName: "英文地点", requiresLocationConsent: false, templateId: "DYN002" },
  { category: "location", displayName: "城市地点", requiresLocationConsent: false, templateId: "DYN003" },
  { category: "location", displayName: "经纬地点", requiresLocationConsent: true, templateId: "DYN004" },
  { category: "other", displayName: "用户名组合", requiresLocationConsent: false, templateId: "DYN007" },
  { category: "time", displayName: "月与时间", requiresLocationConsent: false, templateId: "DYN008" },
  { category: "time", displayName: "完整日期", requiresLocationConsent: false, templateId: "DYN011" },
  { category: "time", displayName: "数字时间", requiresLocationConsent: false, templateId: "DYN012" },
  { category: "identity", displayName: "创作署名", requiresLocationConsent: false, templateId: "DYN015" },
  { category: "identity", displayName: "社交 ID", requiresLocationConsent: false, templateId: "DYN016" },
] as const;

export const P0A_DYNAMIC_STICKERS: readonly DynamicStickerDefinition[] = P0A_DYNAMIC_STICKER_IDS.map((templateId) => {
  const definition = dynamicDefinitions.find((item) => item.templateId === templateId);
  if (!definition) throw new Error(`missing dynamic sticker definition ${templateId}`);
  return definition;
});

function twoDigits(value: number) {
  return String(value).padStart(2, "0");
}

export function normalizeSocialId(value: string) {
  return `@${value.trim().replace(/^@+/, "")}`;
}

function snapshotFor(templateId: DynamicTemplateId, context: DynamicProviderContext) {
  const year = String(context.now.getFullYear());
  const month = twoDigits(context.now.getMonth() + 1);
  const day = twoDigits(context.now.getDate());
  const hour = twoDigits(context.now.getHours());
  const minute = twoDigits(context.now.getMinutes());
  if (templateId === "DYN001") return { fields: { title: context.location?.formattedValue ?? "输入地点" }, value: context.location?.formattedValue ?? "输入地点" };
  if (templateId === "DYN002") return { fields: { city_en: context.location?.formattedValue ?? "LOCATION", title: context.location?.formattedValue ?? "输入地点" }, value: (context.location?.formattedValue ?? "LOCATION").toUpperCase() };
  if (templateId === "DYN003") return { fields: { city: context.location?.formattedValue ?? "城市", title: context.location?.formattedValue ?? "输入地点" }, value: context.location?.formattedValue ?? "城市 · 输入地点" };
  if (templateId === "DYN004") {
    if (context.location?.latitude === undefined || context.location.longitude === undefined) throw new Error("dynamic_location_consent_required");
    return {
      fields: { city: context.location.formattedValue, latitude: context.location.latitude, longitude: context.location.longitude },
      value: `${context.location.formattedValue}\n${context.location.latitude.toFixed(4)}, ${context.location.longitude.toFixed(4)}`,
    };
  }
  if (templateId === "DYN007") {
    const nickname = normalizeSocialId(context.profile.socialId);
    return { fields: { nickname }, value: nickname };
  }
  if (templateId === "DYN008") return { fields: { hour, minute, month }, value: `${month}月 · ${hour}:${minute}` };
  if (templateId === "DYN011") return { fields: { day, month, year }, value: `${year}.${month}.${day}` };
  if (templateId === "DYN012") return { fields: { font_substitution: "FONT081", hour, minute }, value: `${hour}:${minute}` };
  if (templateId === "DYN015") return { fields: { nickname: context.profile.creatorName }, value: context.profile.creatorName };
  return { fields: { nickname: normalizeSocialId(context.profile.socialId) }, value: normalizeSocialId(context.profile.socialId) };
}

export function createDynamicStickerElement(
  templateId: DynamicTemplateId,
  context: DynamicProviderContext,
  identity: CanvasElementIdentity,
  zIndex: number,
): CanvasElement {
  if (!P0A_DYNAMIC_STICKERS.some((item) => item.templateId === templateId)) throw new Error("dynamic_template_unavailable");
  const snapshot = snapshotFor(templateId, context);
  return {
    created_at: identity.createdAt,
    dynamic_fields: snapshot.fields,
    element_id: identity.elementId,
    ...(templateId === "DYN004" && context.location?.latitude !== undefined && context.location.longitude !== undefined
      ? { coordinates: { latitude: context.location.latitude, longitude: context.location.longitude } }
      : {}),
    ...(templateId === "DYN012" ? { font_override: "FONT081" } : {}),
    formatted_value: snapshot.value,
    opacity: 1,
    position: { x: 0.5, y: 0.5 },
    resource_version: DYNAMIC_RESOURCE_VERSION,
    rotation: 0,
    scale: { x: 1, y: 1 },
    style_parameters: {
      provider: "typescript-declarative-v1",
      ...(templateId === "DYN012" ? { font_substitution_disclosure: "DIN_MediumAlternate.otf missing; FONT081 Lexend Deca substitute" } : {}),
    },
    template_or_asset_id: templateId,
    type: "dynamic_sticker",
    z_index: zIndex,
  };
}

export function overrideDynamicStickerValue(element: CanvasElement, formattedValue: string): CanvasElement {
  if (element.type !== "dynamic_sticker") throw new Error("dynamic_element_required");
  const value = formattedValue.trim();
  if (!value) throw new Error("dynamic_value_required");
  return {
    ...structuredClone(element),
    dynamic_fields: { ...structuredClone(element.dynamic_fields ?? {}), display_override: value },
    formatted_value: value,
  };
}

export interface LocationResult {
  formattedValue: string;
  latitude: number;
  longitude: number;
}

export class LocationConsentGate {
  constructor(private readonly adapter: {
    geolocate: () => Promise<{ latitude: number; longitude: number }>;
    reverseGeocode: (coordinates: { latitude: number; longitude: number }) => Promise<string>;
  }) {}

  reject() {
    return undefined;
  }

  async confirm(): Promise<LocationResult> {
    const coordinates = await this.adapter.geolocate();
    if (!Number.isFinite(coordinates.latitude) || coordinates.latitude < -90 || coordinates.latitude > 90
      || !Number.isFinite(coordinates.longitude) || coordinates.longitude < -180 || coordinates.longitude > 180) {
      throw new Error("dynamic_location_invalid");
    }
    const formattedValue = (await this.adapter.reverseGeocode(coordinates)).trim();
    if (!formattedValue) throw new Error("dynamic_location_unavailable");
    return { ...coordinates, formattedValue };
  }
}

export function browserGeolocate() {
  return new Promise<{ latitude: number; longitude: number }>((resolve, reject) => {
    if (!navigator.geolocation) {
      reject(new Error("dynamic_location_unsupported"));
      return;
    }
    navigator.geolocation.getCurrentPosition(
      (position) => resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude }),
      () => reject(new Error("dynamic_location_denied")),
      { enableHighAccuracy: false, maximumAge: 0, timeout: 10_000 },
    );
  });
}
