import { createAdminClient } from "@/lib/supabase-admin";
import {
  PICKUP_PROVIDER_ID,
  PICKUP_PROVIDER_LABEL,
  type ShippingOption,
  type ShippingPackageMetrics,
  type ShippingProviderResult,
  sanitizePostalCode,
} from "@/lib/catalog-shipping";

type MelhorEnvioCompany = {
  name: string;
  picture: string | null;
};

type MelhorEnvioOption = {
  id: string | number;
  name: string;
  price: string | number;
  delivery_time: number;
  currency: string;
  error?: string | boolean | null;
  company: MelhorEnvioCompany;
};

type IntegrationRow = {
  provider: string;
  token: string | null;
  settings: Record<string, unknown> | null;
};

function isMelhorEnvioOption(value: unknown): value is MelhorEnvioOption {
  if (!value || typeof value !== "object") return false;
  const record = value as Record<string, unknown>;
  const company = record.company as Record<string, unknown> | undefined;
  return typeof record.id !== "undefined" &&
    typeof record.name === "string" &&
    typeof record.price !== "undefined" &&
    typeof record.delivery_time === "number" &&
    typeof record.currency === "string" &&
    typeof company?.name === "string";
}

function extractDeliveryTime(value: unknown) {
  if (typeof value === "number" && Number.isFinite(value) && value >= 0) return Math.round(value);
  if (typeof value === "string") {
    const parsed = Number(value);
    if (Number.isFinite(parsed) && parsed >= 0) return Math.round(parsed);
  }
  if (value && typeof value === "object") {
    const record = value as Record<string, unknown>;
    const min = Number(record.min);
    const max = Number(record.max);
    if (Number.isFinite(min) && min >= 0) return Math.round(min);
    if (Number.isFinite(max) && max >= 0) return Math.round(max);
  }
  return null;
}

function parseProviderErrorMessage(raw: string, providerLabel: string) {
  const trimmed = raw.trim();
  if (!trimmed) return `Erro ao consultar ${providerLabel}.`;
  try {
    const parsed = JSON.parse(trimmed) as { message?: unknown; error?: unknown; errors?: Record<string, unknown> };
    const directMessage =
      typeof parsed.message === "string"
        ? parsed.message
        : typeof parsed.error === "string"
          ? parsed.error
          : "";
    if (parsed.errors && typeof parsed.errors === "object") {
      for (const value of Object.values(parsed.errors)) {
        if (Array.isArray(value)) {
          const first = value.find((item) => typeof item === "string");
          if (typeof first === "string" && first.trim()) return first.trim();
        }
        if (typeof value === "string" && value.trim()) return value.trim();
      }
    }
    if (directMessage.trim()) return directMessage.trim();
  } catch {
    return trimmed;
  }
  return `Erro ao consultar ${providerLabel}.`;
}

function isNoResultError(raw: string) {
  const message = raw.toLowerCase();
  if (message.includes("no_result")) return true;
  try {
    const parsed = JSON.parse(raw) as { errors?: Record<string, unknown> };
    const errors = parsed?.errors;
    if (!errors || typeof errors !== "object") return false;
    return Object.keys(errors).some((key) => key.toLowerCase().includes("no_result"));
  } catch {
    return false;
  }
}

function isServicesRequiredError(raw: string) {
  const message = raw.toLowerCase();
  return message.includes("services") && (message.includes("obrigatorio") || message.includes("obrigatório"));
}

function mapSuperFreteOptions(rawData: unknown): ShippingOption[] {
  const getCarrierFallbackLogo = (carrierName: string) => {
    const value = carrierName.toLowerCase();
    if (value.includes("correios")) return "https://www.correios.com.br/favicon.ico";
    if (value.includes("jadlog")) return "https://www.jadlog.com.br/favicon.ico";
    if (value.includes("loggi")) return "https://www.loggi.com/favicon.ico";
    return undefined;
  };

  const asArray = Array.isArray(rawData)
    ? rawData
    : (rawData && typeof rawData === "object" && Array.isArray((rawData as { data?: unknown[] }).data))
      ? (rawData as { data: unknown[] }).data
      : [];

  const options: ShippingOption[] = [];

  asArray.forEach((item, index) => {
    if (!item || typeof item !== "object") return;
    const record = item as Record<string, unknown>;
    const id = record.id ?? record.service_id ?? record.uuid ?? index;
    const service = typeof record.name === "string"
      ? record.name
      : typeof record.service === "string"
        ? record.service
        : "Serviço";
    const companyRaw = record.company;
    const companyName =
      companyRaw && typeof companyRaw === "object" && typeof (companyRaw as Record<string, unknown>).name === "string"
        ? String((companyRaw as Record<string, unknown>).name)
        : typeof record.company_name === "string"
          ? String(record.company_name)
          : "SuperFrete";
    const companyPicture =
      companyRaw && typeof companyRaw === "object" && typeof (companyRaw as Record<string, unknown>).picture === "string"
        ? String((companyRaw as Record<string, unknown>).picture)
        : companyRaw && typeof companyRaw === "object" && typeof (companyRaw as Record<string, unknown>).logo === "string"
          ? String((companyRaw as Record<string, unknown>).logo)
          : undefined;
    const priceCandidate = record.price ?? record.custom_price ?? record.total_price ?? record.shipping_price;
    const price = Number(priceCandidate);
    const deliveryTime = extractDeliveryTime(record.delivery_time ?? record.delivery_range ?? record.delivery_days);
    if (!Number.isFinite(price) || price < 0 || deliveryTime === null) return;

    options.push({
      id: String(id),
      provider: "superfrete",
      provider_label: "SuperFrete",
      name: companyName,
      service,
      price,
      delivery_time: deliveryTime,
      logo_url:
        (typeof record.picture === "string" ? record.picture : undefined) ||
        companyPicture ||
        getCarrierFallbackLogo(companyName),
      currency: typeof record.currency === "string" ? record.currency : "BRL",
    });
  });

  return options;
}

type PickupLocationRow = {
  id: string;
  name: string | null;
  price: number | string | null;
  ready_in_days: number | null;
  zip: string | null;
  street: string | null;
  number: string | null;
  complement: string | null;
  neighborhood: string | null;
  city: string | null;
  state: string | null;
  instructions: string | null;
};

const PICKUP_LOCATION_COLUMNS =
  "id,name,price,ready_in_days,zip,street,number,complement,neighborhood,city,state,instructions";

function buildPickupAddressSummary(row: PickupLocationRow) {
  const zip = sanitizePostalCode(row.zip);
  return [
    [String(row.street || "").trim(), String(row.number || "").trim()].filter(Boolean).join(", "),
    String(row.complement || "").trim(),
    String(row.neighborhood || "").trim(),
    [String(row.city || "").trim(), String(row.state || "").trim().toUpperCase()].filter(Boolean).join(" / "),
    zip.length === 8 ? `CEP ${zip.slice(0, 5)}-${zip.slice(5)}` : "",
  ]
    .filter(Boolean)
    .join(" • ");
}

function mapPickupLocationToOption(row: PickupLocationRow): ShippingOption {
  const priceCandidate = Number(row.price);
  const readyCandidate = Number(row.ready_in_days);
  const name = String(row.name || "").trim() || "Balcão de retirada";

  return {
    id: String(row.id),
    provider: PICKUP_PROVIDER_ID,
    provider_label: PICKUP_PROVIDER_LABEL,
    /* `service` e o titulo do cartao e `name` a linha de apoio, igual as
       transportadoras: la sao "SEDEX" e "Correios", aqui o nome do balcao e o
       endereco onde ele fica. */
    service: name,
    name: buildPickupAddressSummary(row) || PICKUP_PROVIDER_LABEL,
    price: Number.isFinite(priceCandidate) && priceCandidate > 0 ? Number(priceCandidate.toFixed(2)) : 0,
    delivery_time: Number.isFinite(readyCandidate) && readyCandidate > 0 ? Math.trunc(readyCandidate) : 0,
    currency: "BRL",
    pickup: {
      location_id: String(row.id),
      name,
      address_summary: buildPickupAddressSummary(row),
      instructions: String(row.instructions || "").trim(),
    },
  };
}

async function resolveStoreProfileId(admin: ReturnType<typeof createAdminClient>, slug: string) {
  const { data: profile, error: profileError } = await admin
    .from("profiles")
    .select("id")
    .eq("slug", slug)
    .maybeSingle();

  if (profileError) {
    throw new Error(`Erro ao localizar a loja para frete: ${profileError.message}`);
  }
  if (!profile?.id) {
    throw new Error("Loja não encontrada.");
  }
  return String(profile.id);
}

/**
 * Balcoes de retirada ativos da loja, ja no formato de opcao de frete.
 *
 * Nao dependem de CEP nem das medidas do pacote: uma loja que so trabalha com
 * retirada consegue vender mesmo sem integracao de frete e sem peso cadastrado
 * nos produtos.
 */
export async function fetchCatalogPickupOptions(
  admin: ReturnType<typeof createAdminClient>,
  slug: string
): Promise<ShippingOption[]> {
  const profileId = await resolveStoreProfileId(admin, slug);
  return fetchCatalogPickupOptionsByProfile(admin, profileId);
}

export async function fetchCatalogPickupOptionsByProfile(
  admin: ReturnType<typeof createAdminClient>,
  profileId: string
): Promise<ShippingOption[]> {
  const { data, error } = await admin
    .from("catalog_pickup_locations")
    .select(PICKUP_LOCATION_COLUMNS)
    .eq("user_id", profileId)
    .eq("active", true)
    .order("position", { ascending: true })
    .order("created_at", { ascending: true });

  if (error) {
    /* A tabela pode nao existir em ambientes que ainda nao rodaram a migracao.
       Retirada e um extra: nao pode derrubar a cotacao das transportadoras. */
    return [];
  }

  return ((data || []) as PickupLocationRow[]).map(mapPickupLocationToOption);
}

async function getStoreShippingContext(admin: ReturnType<typeof createAdminClient>, slug: string) {
  const profileId = await resolveStoreProfileId(admin, slug);

  const { data: integrations, error: integrationsError } = await admin
    .from("integrations")
    .select("provider,token,settings")
    .eq("user_id", profileId)
    .in("provider", ["melhor_envio", "superfrete"])
    .eq("active", true);

  if (integrationsError) {
    throw new Error(`Erro ao carregar integrações de frete: ${integrationsError.message}`);
  }

  const byProvider = new Map<string, { token?: string; settings?: Record<string, unknown> }>();
  ((integrations || []) as IntegrationRow[]).forEach((integration) => {
    byProvider.set(integration.provider, {
      token: integration.token || undefined,
      settings: integration.settings || {},
    });
  });

  const fallbackOriginZip = "01001000";

  return {
    profileId,
    byProvider,
    fallbackOriginZip,
  };
}

export async function getCatalogShippingStatus(admin: ReturnType<typeof createAdminClient>, slug: string) {
  const ctx = await getStoreShippingContext(admin, slug);
  const melhorEnvio = Boolean(ctx.byProvider.get("melhor_envio")?.token);
  const superfrete = Boolean(ctx.byProvider.get("superfrete")?.token);
  const pickupOptions = await fetchCatalogPickupOptionsByProfile(admin, ctx.profileId);

  return {
    /* `configured` continua respondendo so pelas transportadoras: e ele que
       libera o botao de cotar por CEP. A retirada vem separada porque aparece
       na vitrine sem nenhuma cotacao. */
    configured: melhorEnvio || superfrete,
    providers: {
      melhor_envio: melhorEnvio,
      superfrete,
    },
    pickup: pickupOptions.length > 0,
    pickup_options: pickupOptions,
  };
}

export async function calculateCatalogShippingQuotes(
  admin: ReturnType<typeof createAdminClient>,
  params: {
    slug: string;
    destinationZip: string;
    packageMetrics: ShippingPackageMetrics;
  }
) {
  const { slug, destinationZip, packageMetrics } = params;
  const safeDestinationZip = sanitizePostalCode(destinationZip);
  if (safeDestinationZip.length !== 8) {
    throw new Error("Informe um CEP válido.");
  }

  const ctx = await getStoreShippingContext(admin, slug);
  if (!ctx.byProvider.get("melhor_envio") && !ctx.byProvider.get("superfrete")) {
    throw new Error("Nenhuma integração de frete configurada.");
  }

  const providerResults: ShippingProviderResult[] = [];

  const melhorEnvioIntegration = ctx.byProvider.get("melhor_envio");
  if (melhorEnvioIntegration?.token) {
    const env = String(melhorEnvioIntegration.settings?.env || "production") === "sandbox" ? "sandbox" : "production";
    const fromZip = sanitizePostalCode(melhorEnvioIntegration.settings?.origin_zip) || ctx.fallbackOriginZip;
    const baseUrl = env === "production"
      ? "https://melhorenvio.com.br/api/v2/me/shipment/calculate"
      : "https://sandbox.melhorenvio.com.br/api/v2/me/shipment/calculate";

    const melhorEnvioPayload = {
      from: { postal_code: fromZip },
      to: { postal_code: safeDestinationZip },
      package: {
        height: packageMetrics.height,
        width: packageMetrics.width,
        length: packageMetrics.length,
        weight: packageMetrics.weight,
      },
      options: {
        insurance_value: 0,
        receipt: false,
        own_hand: false,
      },
    };

    try {
      const response = await fetch(baseUrl, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
          Authorization: `Bearer ${melhorEnvioIntegration.token}`,
          "User-Agent": "Ktalogu/1.0 (integracao@ktalogu.com.br)",
        },
        body: JSON.stringify(melhorEnvioPayload),
      });

      if (!response.ok) {
        const errorText = await response.text();
        providerResults.push({
          provider: "melhor_envio",
          provider_label: "Melhor Envio",
          configured: true,
          options: [],
          error: parseProviderErrorMessage(errorText, "Melhor Envio"),
        });
      } else {
        const rawData = (await response.json()) as unknown;
        const options = (Array.isArray(rawData) ? rawData : [rawData])
          .filter(isMelhorEnvioOption)
          .filter((opt) => !opt.error)
          .map((opt) => ({
            id: String(opt.id),
            provider: "melhor_envio" as const,
            provider_label: "Melhor Envio",
            name: opt.company.name,
            service: opt.name,
            price: Number(opt.price),
            delivery_time: opt.delivery_time,
            logo_url: opt.company.picture || undefined,
            currency: opt.currency,
          }))
          .filter((option) => Number.isFinite(option.price) && option.price >= 0);

        providerResults.push({
          provider: "melhor_envio",
          provider_label: "Melhor Envio",
          configured: true,
          options,
        });
      }
    } catch (error) {
      providerResults.push({
        provider: "melhor_envio",
        provider_label: "Melhor Envio",
        configured: true,
        options: [],
        error: error instanceof Error ? error.message : "Erro ao consultar Melhor Envio.",
      });
    }
  }

  const superFreteIntegration = ctx.byProvider.get("superfrete");
  if (superFreteIntegration?.token) {
    const preferredEnv = String(superFreteIntegration.settings?.env || "production") === "sandbox" ? "sandbox" : "production";
    const envAttempts = preferredEnv === "production" ? (["production", "sandbox"] as const) : (["sandbox", "production"] as const);
    const fromZip = sanitizePostalCode(superFreteIntegration.settings?.origin_zip) || ctx.fallbackOriginZip;
    const weightInGrams = Math.max(1, Math.round(packageMetrics.weight * 1000));

    try {
      let lastErrorMessage = "Erro ao consultar SuperFrete.";
      let resolvedOptions: ShippingOption[] = [];

      for (const envAttempt of envAttempts) {
        const baseUrl = envAttempt === "production"
          ? "https://api.superfrete.com/api/v0/calculator"
          : "https://sandbox.superfrete.com/api/v0/calculator";
        /* Serviços PAC (1), SEDEX (2) e Mini Envios (17), em texto separado por vírgula:
           em lista ([1,2,17]) a SuperFrete responde 500 "data.services.split is not a function". */
        const serviceIds = "1,2,17";
        const payloadAttempts = [
          {
            from: { postal_code: fromZip },
            to: { postal_code: safeDestinationZip },
            package: {
              height: packageMetrics.height,
              width: packageMetrics.width,
              length: packageMetrics.length,
              weight: packageMetrics.weight,
            },
            services: serviceIds,
          },
          {
            from: { postal_code: fromZip },
            to: { postal_code: safeDestinationZip },
            package: {
              height: packageMetrics.height,
              width: packageMetrics.width,
              length: packageMetrics.length,
              weight: weightInGrams,
            },
            services: serviceIds,
          },
          {
            from: { postal_code: fromZip },
            to: { postal_code: safeDestinationZip },
            package: {
              height: packageMetrics.height,
              width: packageMetrics.width,
              length: packageMetrics.length,
              weight: packageMetrics.weight,
            },
          },
        ];

        for (const payload of payloadAttempts) {
          const response = await fetch(baseUrl, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Accept: "application/json",
              Authorization: `Bearer ${superFreteIntegration.token}`,
              "User-Agent": "Ktalogu (integracao@ktalogu.com.br)",
            },
            body: JSON.stringify(payload),
          });

          if (!response.ok) {
            const errorText = await response.text();
            const parsedMessage = parseProviderErrorMessage(errorText, "SuperFrete");
            /* O erro que vale é o do ambiente da loja: o outro só é tentado de reserva
               (e o token de produção sempre dá "Token inválida" no de testes). */
            if (envAttempt === preferredEnv) {
              lastErrorMessage = parsedMessage.startsWith("Erro ao consultar SuperFrete")
                ? `${parsedMessage} (HTTP ${response.status})`
                : parsedMessage;
            }
            if (isNoResultError(errorText) || isServicesRequiredError(errorText)) continue;
            if (response.status === 401 || response.status === 403) break;
            continue;
          }

          const rawData = (await response.json()) as unknown;
          const mappedOptions = mapSuperFreteOptions(rawData);
          if (mappedOptions.length > 0) {
            resolvedOptions = mappedOptions;
            break;
          }
        }

        if (resolvedOptions.length > 0) break;
      }

      providerResults.push({
        provider: "superfrete",
        provider_label: "SuperFrete",
        configured: true,
        options: resolvedOptions,
        ...(resolvedOptions.length > 0 ? {} : { error: lastErrorMessage }),
      });
    } catch (error) {
      providerResults.push({
        provider: "superfrete",
        provider_label: "SuperFrete",
        configured: true,
        options: [],
        error: error instanceof Error ? error.message : "Erro ao consultar SuperFrete.",
      });
    }
  }

  return providerResults;
}
