import {
  codigoValido,
  erroDoCupom,
  gerarCodigo,
  lerCupom,
  type AplicacaoDoCupom,
  type BaseDoMinimo,
  type Cupom,
  type EscopoDoCupom,
  type PublicoDoCupom,
  type TipoDoCupom,
} from "@/lib/regras-do-cupom";

/*
  O formulário do cupom no painel: o estado da gaveta, a ida e a volta para a
  linha do banco e os modelos prontos. A conta e a validação são as da loja
  (lib/regras-do-cupom.ts), para o "como o cliente vê" dizer exatamente o
  que o pedido vai cobrar.
*/

export type LinhaDoCupom = Record<string, unknown> & {
  id: string;
  user_id: string;
  code: string;
  active: boolean;
  created_at?: string | null;
};

export type FormularioDoCupom = {
  code: string;
  name: string;
  type: TipoDoCupom;
  value: number;
  max_discount: number;
  shipping_max: number;
  shipping_states: string[];
  scope: EscopoDoCupom;
  scope_category_ids: string[];
  scope_product_ids: string[];
  exclude_category_ids: string[];
  exclude_product_ids: string[];
  min_total: number;
  min_items: number;
  min_scope: BaseDoMinimo;
  audience: PublicoDoCupom;
  audience_client_ids: string[];
  usage_limit: number;
  usage_limit_per_client: number;
  weekdays: number[];
  hours_start: string;
  hours_end: string;
  /** "AAAA-MM-DDTHH:MM", no fuso de quem está no painel (o input datetime-local). */
  starts_at: string;
  ends_at: string;
  application: AplicacaoDoCupom;
  show_in_store: boolean;
  /** Pode ir no pedido junto com um cupom do outro tipo (frete grátis + desconto). */
  combinable: boolean;
  active: boolean;
};

export function formularioVazio(): FormularioDoCupom {
  return {
    code: "",
    name: "",
    type: "percent",
    value: 10,
    max_discount: 0,
    shipping_max: 0,
    shipping_states: [],
    scope: "all",
    scope_category_ids: [],
    scope_product_ids: [],
    exclude_category_ids: [],
    exclude_product_ids: [],
    min_total: 0,
    min_items: 0,
    min_scope: "cart",
    audience: "all",
    audience_client_ids: [],
    usage_limit: 0,
    usage_limit_per_client: 0,
    weekdays: [],
    hours_start: "",
    hours_end: "",
    starts_at: "",
    ends_at: "",
    application: "code",
    show_in_store: false,
    combinable: true,
    active: true,
  };
}

function paraOCampoDeData(valor: unknown) {
  if (!valor) return "";
  const d = new Date(String(valor));
  if (Number.isNaN(d.getTime())) return "";
  const dois = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${dois(d.getMonth() + 1)}-${dois(d.getDate())}T${dois(d.getHours())}:${dois(d.getMinutes())}`;
}

function paraOBanco(valor: string) {
  if (!valor) return null;
  const d = new Date(valor);
  return Number.isNaN(d.getTime()) ? null : d.toISOString();
}

export function formularioDe(linha: LinhaDoCupom): FormularioDoCupom {
  const c = lerCupom(linha);
  return {
    code: String(linha.code ?? ""),
    name: c.name ?? "",
    type: c.type,
    value: c.type === "free_shipping" ? 0 : c.value,
    max_discount: c.max_discount ?? 0,
    shipping_max: c.shipping_max ?? 0,
    shipping_states: c.shipping_states,
    scope: c.scope,
    scope_category_ids: c.scope_category_ids,
    scope_product_ids: c.scope_product_ids,
    exclude_category_ids: c.exclude_category_ids,
    exclude_product_ids: c.exclude_product_ids,
    min_total: c.min_total,
    min_items: c.min_items,
    min_scope: c.min_scope,
    audience: c.audience,
    audience_client_ids: c.audience_client_ids,
    usage_limit: c.usage_limit ?? 0,
    usage_limit_per_client: c.usage_limit_per_client ?? 0,
    weekdays: c.weekdays,
    hours_start: c.hours_start ?? "",
    hours_end: c.hours_end ?? "",
    starts_at: paraOCampoDeData(c.starts_at),
    ends_at: paraOCampoDeData(c.ends_at),
    application: c.application,
    show_in_store: c.show_in_store,
    combinable: c.combinable,
    active: c.active,
  };
}

/** A linha que vai para catalog_coupons (sem id nem user_id). */
export function linhaDoFormulario(f: FormularioDoCupom) {
  const positivo = (n: number) => (Number.isFinite(n) && n > 0 ? n : null);
  return {
    code: f.code.trim().toUpperCase(),
    name: f.name.trim() || null,
    type: f.type,
    value: f.type === "free_shipping" ? 0 : Number(f.value) || 0,
    max_discount: f.type === "percent" ? positivo(f.max_discount) : null,
    shipping_max: f.type === "free_shipping" ? positivo(f.shipping_max) : null,
    shipping_states: f.type === "free_shipping" ? f.shipping_states : [],
    scope: f.scope,
    scope_category_ids: f.scope === "categories" ? f.scope_category_ids : [],
    scope_product_ids: f.scope === "products" ? f.scope_product_ids : [],
    exclude_category_ids: f.exclude_category_ids,
    exclude_product_ids: f.exclude_product_ids,
    min_total: Math.max(Number(f.min_total) || 0, 0),
    min_items: Math.max(Math.floor(Number(f.min_items) || 0), 0),
    min_scope: f.min_scope,
    audience: f.audience,
    audience_client_ids: f.audience === "clients" ? f.audience_client_ids : [],
    usage_limit: positivo(Math.floor(f.usage_limit)),
    usage_limit_per_client: f.audience === "first_purchase" ? null : positivo(Math.floor(f.usage_limit_per_client)),
    weekdays: f.weekdays,
    hours_start: f.hours_start || null,
    hours_end: f.hours_end || null,
    starts_at: paraOBanco(f.starts_at),
    ends_at: paraOBanco(f.ends_at),
    application: f.application,
    show_in_store: f.application === "code" ? f.show_in_store : false,
    combinable: f.combinable,
    active: f.active,
  };
}

/** O cupom do formulário pela regra da loja (para a prévia e a validação). */
export function cupomDoFormulario(f: FormularioDoCupom, id = "previa"): Cupom {
  return lerCupom({ id, ...linhaDoFormulario(f) });
}

/** O erro que impede salvar, em português, ou null. */
export function erroDoFormulario(f: FormularioDoCupom, codigoOriginal: string | null): string | null {
  const codigo = f.code.trim().toUpperCase();
  if (!codigo) return "Dê um código ao cupom (é o que o cliente digita).";
  /* Código antigo com espaço continua valendo; só o código novo segue a regra. */
  if (codigo !== (codigoOriginal ?? "").toUpperCase() && !codigoValido(codigo)) {
    return "Código com 3 a 30 letras, números ou hífen, sem espaço. Ex.: BEMVINDO10.";
  }
  if (f.ends_at && f.starts_at && new Date(f.ends_at).getTime() < new Date(f.starts_at).getTime()) return "O fim da validade é antes do começo.";
  return erroDoCupom(cupomDoFormulario(f));
}

/* ------------------------------------------------------------ modelos prontos */

export type ModeloDeCupom = {
  id: string;
  titulo: string;
  texto: string;
  cor: string;
  montar: () => FormularioDoCupom;
};

export const MODELOS_DE_CUPOM: ModeloDeCupom[] = [
  {
    id: "boas-vindas",
    titulo: "Boas-vindas 10%",
    texto: "10% para quem chega, com código e um uso por cliente.",
    cor: "var(--ks-brand-600)",
    montar: () => ({ ...formularioVazio(), code: "BEMVINDO10", name: "Boas-vindas", value: 10, usage_limit_per_client: 1, show_in_store: true }),
  },
  {
    id: "frete-gratis",
    titulo: "Frete grátis acima de R$ 199",
    texto: "Zera o frete em compras a partir de R$ 199, aplicado sozinho no carrinho.",
    cor: "var(--ks-emerald)",
    montar: () => ({ ...formularioVazio(), code: "FRETEGRATIS", name: "Frete grátis", type: "free_shipping", value: 0, min_total: 199, application: "automatic" }),
  },
  {
    id: "primeira-compra",
    titulo: "Primeira compra",
    texto: "R$ 20 de desconto só na primeira compra de quem tem conta na loja.",
    cor: "var(--ks-pink)",
    montar: () => ({ ...formularioVazio(), code: "PRIMEIRA20", name: "Primeira compra", type: "value", value: 20, min_total: 100, audience: "first_purchase" }),
  },
  {
    id: "campanha",
    titulo: "Campanha de categoria",
    texto: "15% numa categoria escolhida, por tempo limitado e para os primeiros 100.",
    cor: "var(--ks-amber)",
    montar: () => {
      const fim = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
      fim.setHours(23, 59, 0, 0);
      const dois = (n: number) => String(n).padStart(2, "0");
      return {
        ...formularioVazio(),
        code: gerarCodigo("CAMPANHA"),
        name: "Campanha da semana",
        value: 15,
        scope: "categories",
        usage_limit: 100,
        ends_at: `${fim.getFullYear()}-${dois(fim.getMonth() + 1)}-${dois(fim.getDate())}T23:59`,
      };
    },
  },
];
