import crypto from "node:crypto";
import { promises as dns } from "node:dns";
import type { SupabaseClient } from "@supabase/supabase-js";
import {
  createCloudflareCustomHostname,
  deleteCloudflareCustomHostname,
  getCloudflareCustomHostname,
  getCloudflareSaasConfig,
  type CloudflareCustomHostname,
} from "./cloudflare-saas.ts";

/*
 * O domínio próprio da loja (www.minhaloja.com.br no lugar de
 * ktalogu.com.br/minhaloja): ler, cadastrar, conferir e remover.
 *
 * Saiu de dentro das rotas /api/catalog/custom-domain (e /verify) para que a
 * tela do painel e o assistente usem exatamente a mesma conta. As rotas
 * continuam respondendo igual; quem confere se a pessoa pode mexer é quem
 * chama (só dono e administrador mexem no domínio).
 *
 * Toda gravação usa a chave de serviço: a tabela profile_custom_domains é
 * fechada para o navegador.
 */

export type DnsRecordRow = {
  type: string;
  host: string;
  value: string;
  host_label?: string;
  required?: boolean;
};

export type DomainRow = {
  domain?: string | null;
  verified?: boolean | null;
  verified_at?: string | null;
  verification_token?: string | null;
  verification_mode?: string | null;
  verification_dns_name?: string | null;
  verification_dns_type?: string | null;
  cf_hostname_id?: string | null;
  cf_hostname_status?: string | null;
  cf_ssl_status?: string | null;
};

export function normalizeDomain(input: string) {
  let value = (input || "").trim().toLowerCase();
  value = value.replace(/^https?:\/\//, "");
  value = value.split("/")[0] || "";
  value = value.split(":")[0] || "";
  if (value.startsWith("www.")) value = value.slice(4);
  return value;
}

export function isValidDomain(domain: string) {
  if (!domain) return false;
  if (domain.length > 253) return false;
  if (domain.includes("..")) return false;
  const labels = domain.split(".");
  if (labels.length < 2) return false;
  return labels.every((label) => /^[a-z0-9-]{1,63}$/.test(label) && !label.startsWith("-") && !label.endsWith("-"));
}

export function getReservedHosts() {
  const configuredPublic = process.env.NEXT_PUBLIC_PUBLIC_CATALOG_BASE_URL || "";
  const configuredAdmin = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
  const extractHost = (raw: string) => {
    if (!raw) return "";
    try {
      return new URL(raw).hostname.toLowerCase();
    } catch {
      return raw.replace(/^https?:\/\//, "").split("/")[0]?.split(":")[0]?.toLowerCase() || "";
    }
  };
  return new Set([
    "localhost",
    "127.0.0.1",
    "ktalogu.com.br",
    "www.ktalogu.com.br",
    "admin.ktalogu.com.br",
    extractHost(configuredPublic),
    extractHost(configuredAdmin),
  ]);
}

const BR_SECOND_LEVEL_SUFFIXES = new Set([
  "com.br",
  "net.br",
  "org.br",
  "gov.br",
  "edu.br",
  "emp.br",
  "ind.br",
  "jus.br",
  "leg.br",
  "mil.br",
  "nom.br",
  "tur.br",
  "wiki.br",
]);

export function getDomainKind(domain: string): "root" | "subdomain" {
  const normalized = String(domain || "").trim().toLowerCase();
  const labels = normalized.split(".").filter(Boolean);
  if (labels.length <= 2) return "root";
  const lastTwo = labels.slice(-2).join(".");
  if (BR_SECOND_LEVEL_SUFFIXES.has(lastTwo)) {
    return labels.length <= 3 ? "root" : "subdomain";
  }
  return labels.length <= 2 ? "root" : "subdomain";
}

export async function readDomainRow(supabase: SupabaseClient, profileId: string) {
  const full = await supabase
    .from("profile_custom_domains")
    .select(
      "domain,verified,verified_at,verification_token,verification_mode,verification_dns_name,verification_dns_type,cf_hostname_id,cf_hostname_status,cf_ssl_status"
    )
    .eq("profile_id", profileId)
    .maybeSingle();
  if (!full.error) return full.data as DomainRow | null;
  if (full.error.code === "42P01") return null;
  const message = String(full.error.message || "").toLowerCase();
  if (!message.includes("does not exist")) throw full.error;
  const legacy = await supabase
    .from("profile_custom_domains")
    .select("domain,verified,verified_at,verification_token")
    .eq("profile_id", profileId)
    .maybeSingle();
  if (legacy.error && legacy.error.code !== "42P01") throw legacy.error;
  return (legacy.data as DomainRow | null) || null;
}

export function mapCloudflareDns(domain: string, result: CloudflareCustomHostname): DnsRecordRow[] {
  const { cnameTarget } = getCloudflareSaasConfig();
  const ownership = result.ownership_verification;
  const records: DnsRecordRow[] = [];
  if (cnameTarget) {
    records.push({
      type: "CNAME",
      host: domain,
      value: cnameTarget,
      host_label: getDomainKind(domain) === "root" ? "@" : domain,
      required: true,
    });
  }
  if (ownership?.name && ownership?.value) {
    records.push({
      type: (ownership.type || "TXT").toUpperCase(),
      host: ownership.name,
      value: ownership.value,
      host_label: ownership.name,
      required: true,
    });
  }
  return records;
}

export function mapCloudflareSslValidationDns(result: CloudflareCustomHostname): DnsRecordRow[] {
  const records: DnsRecordRow[] = [];
  const sslRecords = [...(result.ssl?.validation_records || []), ...(result.ssl?.dcv_delegation_records || [])];
  for (const record of sslRecords) {
    if (record?.txt_name && record?.txt_value) {
      records.push({
        type: "TXT",
        host: record.txt_name,
        value: record.txt_value,
        host_label: record.txt_name,
        required: true,
      });
    }
  }
  return records;
}

export function mergeDnsRecords(...groups: DnsRecordRow[][]) {
  const dedupe = new Map<string, DnsRecordRow>();
  for (const group of groups) {
    for (const record of group) {
      const key = `${record.type}|${record.host}|${record.value}`;
      if (!dedupe.has(key)) dedupe.set(key, record);
    }
  }
  return Array.from(dedupe.values());
}

/* ------------------------------------------------------------------ ler */

export type DominioLido = Record<string, unknown> & {
  domain: string | null;
  verified: boolean | null;
  verification_mode: "legacy" | "cloudflare";
  cloudflare_enabled: boolean;
  domain_kind: "root" | "subdomain";
  requires_provider_apex_support: boolean;
  dns_records: DnsRecordRow[];
};

/** O domínio da loja como está, com os registros de DNS que faltam criar. */
export async function lerDominioPersonalizado(admin: SupabaseClient, profileId: string): Promise<DominioLido> {
  const data = await readDomainRow(admin, profileId);
  const mode = (data?.verification_mode || "legacy") as "legacy" | "cloudflare";
  const { enabled, cnameTarget } = getCloudflareSaasConfig();
  const domainKind = data?.domain ? getDomainKind(data.domain) : "subdomain";
  let dnsRecords: DnsRecordRow[] = data?.domain
    ? mode === "cloudflare"
      ? [
          ...(cnameTarget
            ? [
                {
                  type: "CNAME",
                  host: data.domain,
                  value: cnameTarget,
                  host_label: domainKind === "root" ? "@" : data.domain,
                  required: true,
                },
              ]
            : []),
          ...(data.verification_dns_name && data.verification_token
            ? [
                {
                  type: (data.verification_dns_type || "TXT").toUpperCase(),
                  host: data.verification_dns_name,
                  value: data.verification_token,
                  host_label: data.verification_dns_name,
                  required: true,
                },
              ]
            : []),
        ]
      : data.verification_token
        ? [
            {
              type: "TXT",
              host: `_ktalogu-verification.${data.domain}`,
              value: data.verification_token,
              host_label: `_ktalogu-verification.${data.domain}`,
              required: true,
            },
          ]
        : []
    : [];
  if (mode === "cloudflare" && enabled && data?.cf_hostname_id) {
    try {
      const hostname = await getCloudflareCustomHostname(data.cf_hostname_id);
      dnsRecords = mergeDnsRecords(dnsRecords, mapCloudflareDns(data.domain || "", hostname), mapCloudflareSslValidationDns(hostname));
    } catch {}
  }
  return data
    ? {
        ...data,
        domain: data.domain ?? null,
        verified: data.verified ?? null,
        verification_mode: mode,
        cloudflare_enabled: enabled,
        domain_kind: domainKind,
        requires_provider_apex_support: domainKind === "root",
        dns_records: dnsRecords,
      }
    : {
        domain: null,
        verified: false,
        verification_token: null,
        verification_mode: mode,
        verification_dns_name: null,
        verification_dns_type: null,
        cf_hostname_id: null,
        cf_hostname_status: null,
        cf_ssl_status: null,
        verified_at: null,
        cloudflare_enabled: enabled,
        domain_kind: domainKind,
        requires_provider_apex_support: false,
        dns_records: [],
      };
}

/* ------------------------------------------------------------- cadastrar */

export type Recusa = { ok: false; status: number; error: string; data?: Record<string, unknown>; details?: Record<string, unknown> };

/** Confere o endereço digitado. Volta o domínio limpo (sem https://, sem www.). */
export function conferirDominioPedido(bruto: string): { ok: true; domain: string } | Recusa {
  const normalizedDomain = normalizeDomain(bruto || "");
  if (!isValidDomain(normalizedDomain)) return { ok: false, status: 400, error: "Domínio inválido." };
  /* Nem os endereços da Ktalogu nem nada debaixo deles (loja.ktalogu.com.br,
     admin.ktalogu.com.br): o certificado e o roteamento são da plataforma. */
  const debaixoDe = (host: string) => Boolean(host) && (normalizedDomain === host || normalizedDomain.endsWith(`.${host}`));
  const reservados = getReservedHosts();
  if (reservados.has(normalizedDomain) || ["ktalogu.com.br", ...reservados].some(debaixoDe)) {
    return { ok: false, status: 400, error: "Este domínio não pode ser usado como personalizado." };
  }
  return { ok: true, domain: normalizedDomain };
}

export type DominioCadastrado = {
  domain: string;
  verified: boolean;
  verification_mode: "legacy" | "cloudflare";
  verification_token: string;
  cf_hostname_id: unknown;
  cf_hostname_status: unknown;
  cf_ssl_status: unknown;
  domain_kind: "root" | "subdomain";
  requires_provider_apex_support: boolean;
  dns_records: DnsRecordRow[];
};

/**
 * Cadastra (ou troca) o domínio da loja. `normalizedDomain` já passou por
 * `conferirDominioPedido`. Com a Cloudflare configurada, o domínio é
 * registrado lá e volta com os registros de DNS; sem ela, vale a conferência
 * antiga por um TXT.
 */
export async function cadastrarDominioPersonalizado(
  admin: SupabaseClient,
  profileId: string,
  normalizedDomain: string
): Promise<{ ok: true; data: DominioCadastrado } | Recusa> {
  const existing = await readDomainRow(admin, profileId);
  const cloudflare = getCloudflareSaasConfig();
  const now = new Date().toISOString();
  let payload: Record<string, unknown>;
  let dnsRecords: DnsRecordRow[] = [];
  let mode: "legacy" | "cloudflare" = "legacy";
  const domainKind = getDomainKind(normalizedDomain);

  if (cloudflare.enabled) {
    mode = "cloudflare";
    if (existing?.cf_hostname_id && existing.domain && existing.domain !== normalizedDomain) {
      try {
        await deleteCloudflareCustomHostname(existing.cf_hostname_id);
      } catch {}
    }
    const created = await createCloudflareCustomHostname(normalizedDomain);
    const ownership = created.ownership_verification;
    const sslStatus = String(created.ssl?.status || "");
    const hostnameStatus = String(created.status || "");
    const isActive = sslStatus === "active" && hostnameStatus === "active";
    payload = {
      profile_id: profileId,
      domain: normalizedDomain,
      verification_mode: "cloudflare",
      verification_token: ownership?.value || "",
      verification_dns_name: ownership?.name || null,
      verification_dns_type: ownership?.type?.toUpperCase() || "TXT",
      cf_hostname_id: created.id,
      cf_hostname_status: hostnameStatus || null,
      cf_ssl_status: sslStatus || null,
      verified: isActive,
      verified_at: isActive ? now : null,
      updated_at: now,
    };
    dnsRecords = mergeDnsRecords(mapCloudflareDns(normalizedDomain, created), mapCloudflareSslValidationDns(created));
  } else {
    const verificationToken = crypto.randomBytes(18).toString("hex");
    payload = {
      profile_id: profileId,
      domain: normalizedDomain,
      verification_mode: "legacy",
      verification_token: verificationToken,
      verification_dns_name: `_ktalogu-verification.${normalizedDomain}`,
      verification_dns_type: "TXT",
      cf_hostname_id: null,
      cf_hostname_status: null,
      cf_ssl_status: null,
      verified: false,
      verified_at: null,
      updated_at: now,
    };
    dnsRecords = [
      {
        type: "TXT",
        host: `_ktalogu-verification.${normalizedDomain}`,
        value: verificationToken,
        host_label: `_ktalogu-verification.${normalizedDomain}`,
        required: true,
      },
    ];
  }

  const { error } = await admin.from("profile_custom_domains").upsert([payload], { onConflict: "profile_id" });
  if (error) {
    const code = (error as { code?: string }).code;
    if (code === "23505") return { ok: false, status: 409, error: "Este domínio já está configurado por outra loja." };
    return { ok: false, status: 400, error: error.message };
  }

  return {
    ok: true,
    data: {
      domain: normalizedDomain,
      verified: Boolean(payload.verified),
      verification_mode: mode,
      verification_token: String(payload.verification_token || ""),
      cf_hostname_id: payload.cf_hostname_id || null,
      cf_hostname_status: payload.cf_hostname_status || null,
      cf_ssl_status: payload.cf_ssl_status || null,
      domain_kind: domainKind,
      requires_provider_apex_support: domainKind === "root",
      dns_records: dnsRecords,
    },
  };
}

/* --------------------------------------------------------------- remover */

export async function removerDominioPersonalizado(admin: SupabaseClient, profileId: string): Promise<{ ok: true } | Recusa> {
  const existing = await readDomainRow(admin, profileId);
  const cloudflare = getCloudflareSaasConfig();
  if (cloudflare.enabled && existing?.verification_mode === "cloudflare" && existing.cf_hostname_id) {
    try {
      await deleteCloudflareCustomHostname(existing.cf_hostname_id);
    } catch {}
  }
  const { error } = await admin.from("profile_custom_domains").delete().eq("profile_id", profileId);
  if (error) return { ok: false, status: 400, error: error.message };
  return { ok: true };
}

/* -------------------------------------------------------------- conferir */

function flattenTxtRecords(records: string[][]) {
  return records.map((parts) => parts.join("").trim());
}

/**
 * Confere se o DNS já aponta e, se sim, marca o domínio como verificado.
 * O TXT antigo que não existe faz `dns.resolveTxt` lançar (como sempre fez).
 */
export async function verificarDominioPersonalizado(
  admin: SupabaseClient,
  profileId: string
): Promise<{ ok: true; data: Record<string, unknown> } | Recusa> {
  const domainRow = await readDomainRow(admin, profileId);

  if (!domainRow?.domain || !domainRow?.verification_token) {
    return { ok: false, status: 400, error: "Nenhum domínio configurado para validação." };
  }
  const domainKind = getDomainKind(domainRow.domain);

  const mode = String(domainRow.verification_mode || "legacy");
  const cloudflare = getCloudflareSaasConfig();
  if (mode === "cloudflare" && (!cloudflare.enabled || !domainRow.cf_hostname_id)) {
    return {
      ok: false,
      status: 400,
      error: "Cloudflare for SaaS não está configurado no servidor.",
      data: {
        domain: domainRow.domain,
        verified: false,
        verification_mode: "cloudflare",
        domain_kind: domainKind,
        requires_provider_apex_support: domainKind === "root",
      },
    };
  }
  if (mode === "cloudflare" && cloudflare.enabled && domainRow.cf_hostname_id) {
    const customHostname = await getCloudflareCustomHostname(domainRow.cf_hostname_id);
    const hostnameStatus = String(customHostname.status || "");
    const sslStatus = String(customHostname.ssl?.status || "");
    const isActive = hostnameStatus === "active" && sslStatus === "active";
    const now = new Date().toISOString();

    const { error: updateError } = await admin
      .from("profile_custom_domains")
      .update({
        verified: isActive,
        verified_at: isActive ? now : null,
        cf_hostname_status: hostnameStatus || null,
        cf_ssl_status: sslStatus || null,
        verification_dns_name: customHostname.ownership_verification?.name || domainRow.verification_dns_name || null,
        verification_dns_type: customHostname.ownership_verification?.type?.toUpperCase() || domainRow.verification_dns_type || "TXT",
        verification_token: customHostname.ownership_verification?.value || domainRow.verification_token || "",
        updated_at: now,
      })
      .eq("profile_id", profileId);

    if (updateError) return { ok: false, status: 400, error: updateError.message };

    if (!isActive) {
      return {
        ok: false,
        status: 400,
        error: "Domínio ainda não ativo na Cloudflare. Aguarde a propagação DNS e tente novamente.",
        data: {
          domain: domainRow.domain,
          verified: false,
          verification_mode: "cloudflare",
          cf_hostname_status: hostnameStatus || null,
          cf_ssl_status: sslStatus || null,
          domain_kind: domainKind,
          requires_provider_apex_support: domainKind === "root",
        },
      };
    }

    return {
      ok: true,
      data: {
        domain: domainRow.domain,
        verified: true,
        verification_mode: "cloudflare",
        cf_hostname_status: hostnameStatus || null,
        cf_ssl_status: sslStatus || null,
        domain_kind: domainKind,
        requires_provider_apex_support: domainKind === "root",
      },
    };
  }

  const verificationHost = `_ktalogu-verification.${domainRow.domain}`;
  const txtRecords = await dns.resolveTxt(verificationHost);
  const values = flattenTxtRecords(txtRecords);
  const matched = values.some((value) => value === domainRow.verification_token);

  if (!matched) {
    return {
      ok: false,
      status: 400,
      error: "Token DNS não encontrado. Aguarde a propagação e tente novamente.",
      details: { host: verificationHost, expected: domainRow.verification_token },
    };
  }

  const { error: updateError } = await admin
    .from("profile_custom_domains")
    .update({ verified: true, verified_at: new Date().toISOString(), updated_at: new Date().toISOString() })
    .eq("profile_id", profileId);

  if (updateError) return { ok: false, status: 400, error: updateError.message };

  return {
    ok: true,
    data: {
      domain: domainRow.domain,
      verified: true,
      domain_kind: domainKind,
      requires_provider_apex_support: domainKind === "root",
    },
  };
}
