import type { BrandProfile, BusinessContext, FactSource, GeneratedPost, Project } from "@/types/workflow";
import { MISSING_FACT, UNKNOWN_FACT, isPresentFact, uniqueNonEmpty } from "./facts";
import type { WebsiteIntelligence } from "./website-intelligence";

function pick(
  user: string | undefined,
  website: string | undefined,
  inferred?: string,
): { value: string; source: FactSource } {
  if (isPresentFact(user)) return { value: user!.trim(), source: "user" };
  if (isPresentFact(website) && website !== MISSING_FACT && website !== UNKNOWN_FACT) {
    return { value: website!.trim(), source: "website" };
  }
  if (isPresentFact(inferred)) return { value: inferred!.trim(), source: "inferred" };
  return { value: MISSING_FACT, source: "inferred" };
}

function pickList(
  userText: string | undefined,
  websiteList: string[] | undefined,
): { value: string[]; source: FactSource } {
  const fromUser = userText
    ?.split(/[,;\n]/)
    .map((s) => s.trim())
    .filter((s) => isPresentFact(s));
  if (fromUser?.length) return { value: uniqueNonEmpty(fromUser, 12), source: "user" };
  const fromSite = uniqueNonEmpty(websiteList ?? [], 12);
  if (fromSite.length) return { value: fromSite, source: "website" };
  return { value: [], source: "inferred" };
}

function approvedCaptions(posts?: GeneratedPost[]): string[] {
  return (posts ?? [])
    .filter((p) => p.status === "approved" || p.status === "published")
    .map((p) => p.caption?.trim())
    .filter((c): c is string => Boolean(c))
    .slice(0, 8);
}

export function emptyBusinessContext(): BusinessContext {
  return {
    companyName: MISSING_FACT,
    description: MISSING_FACT,
    industry: MISSING_FACT,
    products: [],
    services: [],
    features: [],
    audience: MISSING_FACT,
    locations: [],
    customerProblems: [],
    painPoints: [],
    businessImpact: [],
    differentiators: [],
    benefits: [],
    useCases: [],
    websiteClaims: [],
    verifiedClaims: [],
    missingInformation: ["company name", "website", "products", "services", "audience"],
    contact: {
      phone: MISSING_FACT,
      email: MISSING_FACT,
      address: MISSING_FACT,
    },
    fieldSources: {},
    confirmed: false,
  };
}

/** Ensure persisted / legacy business context has required nested fields. */
export function normalizeBusinessContext(
  raw: Partial<BusinessContext> | null | undefined,
): BusinessContext | undefined {
  if (!raw || typeof raw !== "object") return undefined;
  const base = emptyBusinessContext();
  return {
    ...base,
    ...raw,
    products: Array.isArray(raw.products) ? raw.products : base.products,
    services: Array.isArray(raw.services) ? raw.services : base.services,
    features: Array.isArray(raw.features) ? raw.features : base.features,
    locations: Array.isArray(raw.locations) ? raw.locations : base.locations,
    customerProblems: Array.isArray(raw.customerProblems)
      ? raw.customerProblems
      : base.customerProblems,
    painPoints: Array.isArray(raw.painPoints) ? raw.painPoints : base.painPoints,
    businessImpact: Array.isArray(raw.businessImpact)
      ? raw.businessImpact
      : base.businessImpact,
    differentiators: Array.isArray(raw.differentiators)
      ? raw.differentiators
      : base.differentiators,
    benefits: Array.isArray(raw.benefits) ? raw.benefits : base.benefits,
    useCases: Array.isArray(raw.useCases) ? raw.useCases : base.useCases,
    websiteClaims: Array.isArray(raw.websiteClaims) ? raw.websiteClaims : base.websiteClaims,
    verifiedClaims: Array.isArray(raw.verifiedClaims)
      ? raw.verifiedClaims
      : base.verifiedClaims,
    missingInformation: Array.isArray(raw.missingInformation)
      ? raw.missingInformation
      : base.missingInformation,
    contact: {
      ...base.contact,
      ...(raw.contact ?? {}),
    },
    fieldSources: raw.fieldSources ?? base.fieldSources,
    confirmed: Boolean(raw.confirmed),
  };
}

/** Build an unconfirmed draft from brand (and optional project hints) when none exists yet. */
export function draftBusinessContextFromBrand(
  brand: BrandProfile,
  projectHint?: { name?: string; website?: string; industry?: string },
): BusinessContext {
  const now = new Date(0).toISOString();
  return buildBusinessContext({
    brand,
    project: {
      id: "draft",
      name: projectHint?.name?.trim() || brand.companyName?.trim() || "",
      website: projectHint?.website?.trim() || "",
      industry: projectHint?.industry?.trim() || brand.industry?.trim() || "",
      timezone: "UTC",
      countries: [],
      status: "active",
      createdAt: now,
      updatedAt: now,
    },
  });
}

/**
 * Build normalized Business Context.
 * Priority: explicit user input > verified website information > AI inference.
 * Never fabricates company facts.
 */
export function buildBusinessContext(input: {
  project: Project;
  brand: BrandProfile;
  website?: WebsiteIntelligence | null;
  approvedPosts?: GeneratedPost[];
  existing?: BusinessContext | null;
}): BusinessContext {
  const { project, brand, website, approvedPosts, existing } = input;

  const company = pick(brand.companyName, website?.companyName, project.name);
  const description = pick(
    undefined,
    website?.about || website?.description,
    brand.tagline,
  );
  const industry = pick(brand.industry, website?.industries?.[0], project.industry);
  const audience = pick(brand.targetAudience, website?.targetAudience);
  const products = pickList(undefined, website?.products);
  const userOffer = pickList(brand.productsServices, website?.services?.map((s) => s.label));
  const services = userOffer.value.length
    ? userOffer
    : { value: [] as string[], source: "inferred" as FactSource };
  const features = pickList(undefined, website?.features);
  const benefits = pickList(undefined, website?.benefits);
  const differentiators = pickList(undefined, website?.differentiators);
  const locations = pickList(undefined, website?.locations);
  const phone = pick(brand.contactPhone, website?.contactPhone === MISSING_FACT ? "" : website?.contactPhone);
  const email = pick(brand.contactEmail, website?.contactEmail === MISSING_FACT ? "" : website?.contactEmail);
  const address = pick(undefined, website?.address === MISSING_FACT ? "" : website?.address);

  const userProblems = existing?.fieldSources.customerProblems === "user" ? existing.customerProblems : [];
  const userPain = existing?.fieldSources.painPoints === "user" ? existing.painPoints : [];
  const userImpact = existing?.fieldSources.businessImpact === "user" ? existing.businessImpact : [];
  const userUseCases = existing?.fieldSources.useCases === "user" ? existing.useCases : [];

  const websiteClaims = uniqueNonEmpty(website?.websiteClaims ?? [], 8);
  const verifiedClaims =
    existing?.fieldSources.verifiedClaims === "user" ? existing.verifiedClaims : [];

  const missingInformation: string[] = [];
  if (!isPresentFact(company.value)) missingInformation.push("company name");
  if (!isPresentFact(description.value)) missingInformation.push("company description");
  if (!isPresentFact(industry.value)) missingInformation.push("industry");
  if (!isPresentFact(audience.value)) missingInformation.push("target audience");
  if (!products.value.length) missingInformation.push("products");
  if (!services.value.length) missingInformation.push("services");
  if (!isPresentFact(phone.value)) missingInformation.push("phone");
  if (!isPresentFact(email.value)) missingInformation.push("email");
  if (!isPresentFact(address.value)) missingInformation.push("address");
  if (!userProblems.length) missingInformation.push("customer problems");
  if (!verifiedClaims.length) missingInformation.push("verified proof / results");
  if (!project.website?.trim()) missingInformation.push("website URL");

  const fieldSources: BusinessContext["fieldSources"] = {
    companyName: company.source,
    description: description.source,
    industry: industry.source,
    audience: audience.source,
    products: products.source,
    services: services.source,
    features: features.source,
    benefits: benefits.source,
    differentiators: differentiators.source,
    locations: locations.source,
    phone: phone.source,
    email: email.source,
    address: address.source,
    customerProblems: userProblems.length ? "user" : "inferred",
    painPoints: userPain.length ? "user" : "inferred",
    businessImpact: userImpact.length ? "user" : "inferred",
    useCases: userUseCases.length ? "user" : "inferred",
    verifiedClaims: verifiedClaims.length ? "user" : "inferred",
  };

  const context: BusinessContext = {
    companyName: company.value,
    description: description.value,
    industry: industry.value,
    products: products.value,
    services: services.value.length ? services.value : [],
    features: features.value,
    audience: audience.value,
    locations: locations.value,
    customerProblems: userProblems,
    painPoints: userPain,
    businessImpact: userImpact,
    differentiators: differentiators.value,
    benefits: benefits.value,
    useCases: userUseCases,
    websiteClaims,
    verifiedClaims,
    missingInformation,
    contact: {
      phone: isPresentFact(phone.value) ? phone.value : MISSING_FACT,
      email: isPresentFact(email.value) ? email.value : MISSING_FACT,
      address: isPresentFact(address.value) ? address.value : MISSING_FACT,
    },
    fieldSources,
    confirmed: existing?.confirmed ?? false,
    confirmedAt: existing?.confirmedAt,
    websiteFetchedAt: website?.fetchedAt,
    websiteOk: website?.ok,
  };

  const approved = approvedCaptions(approvedPosts);
  if (approved.length && !context.useCases.length) {
    context.useCases = approved.map((c) => c.split("\n")[0]!.slice(0, 140));
    context.fieldSources.useCases = "user";
  }

  return preserveUserEdits(existing, context);
}

function preserveUserEdits(
  existing: BusinessContext | null | undefined,
  rebuilt: BusinessContext,
): BusinessContext {
  if (!existing) return rebuilt;
  const next = { ...rebuilt };

  const textKeys = ["companyName", "description", "industry", "audience"] as const;
  for (const key of textKeys) {
    if (existing.fieldSources[key] === "user" && isPresentFact(existing[key])) {
      next[key] = existing[key];
      next.fieldSources[key] = "user";
    }
  }

  const listKeys = [
    "products",
    "services",
    "features",
    "customerProblems",
    "painPoints",
    "businessImpact",
    "differentiators",
    "benefits",
    "useCases",
    "verifiedClaims",
  ] as const;
  for (const key of listKeys) {
    if (existing.fieldSources[key] === "user" && existing[key]?.length) {
      next[key] = existing[key];
      next.fieldSources[key] = "user";
    }
  }

  if (existing.fieldSources.phone === "user" && isPresentFact(existing.contact.phone)) {
    next.contact.phone = existing.contact.phone;
    next.fieldSources.phone = "user";
  }
  if (existing.fieldSources.email === "user" && isPresentFact(existing.contact.email)) {
    next.contact.email = existing.contact.email;
    next.fieldSources.email = "user";
  }

  next.confirmed = existing.confirmed;
  next.confirmedAt = existing.confirmedAt;
  return next;
}

/** Fill empty brand fields from website — never overwrite explicit user input. */
export function suggestBrandFromWebsite(
  brand: BrandProfile,
  website: WebsiteIntelligence | null | undefined,
): Partial<BrandProfile> {
  if (!website?.ok) return {};
  const patch: Partial<BrandProfile> = {};
  if (!isPresentFact(brand.companyName) && isPresentFact(website.companyName)) {
    patch.companyName = website.companyName;
  }
  if (!isPresentFact(brand.tagline) && isPresentFact(website.tagline) && website.tagline.length <= 90) {
    patch.tagline = website.tagline;
  }
  if (!isPresentFact(brand.industry) && website.industries[0]) {
    patch.industry = website.industries[0];
  }
  if (!isPresentFact(brand.targetAudience) && isPresentFact(website.targetAudience)) {
    patch.targetAudience = website.targetAudience;
  }
  if (!isPresentFact(brand.productsServices)) {
    const offer = uniqueNonEmpty(
      [...website.services.map((s) => s.label), ...website.products],
      8,
    );
    if (offer.length) patch.productsServices = offer.join(", ");
  }
  if (!isPresentFact(brand.contactPhone) && isPresentFact(website.contactPhone)) {
    patch.contactPhone = website.contactPhone;
  }
  if (!isPresentFact(brand.contactEmail) && isPresentFact(website.contactEmail)) {
    patch.contactEmail = website.contactEmail;
  }
  return patch;
}

export function formatBusinessContextMarkdown(ctx: BusinessContext): string {
  const list = (items: string[], empty: string) =>
    items.length ? items.map((i) => `- ${i}`).join("\n") : empty;

  return [
    "## Business Context (source of truth)",
    `Company: ${ctx.companyName}`,
    `Description: ${ctx.description}`,
    `Industry: ${ctx.industry}`,
    `Audience: ${ctx.audience}`,
    `Services: ${ctx.services.length ? ctx.services.join("; ") : UNKNOWN_FACT}`,
    `Products: ${ctx.products.length ? ctx.products.join("; ") : UNKNOWN_FACT}`,
    ctx.features.length ? `Features: ${ctx.features.join("; ")}` : `Features: ${UNKNOWN_FACT}`,
    `Phone: ${ctx.contact.phone}`,
    `Email: ${ctx.contact.email}`,
    `Address: ${ctx.contact.address}`,
    ctx.locations.length ? `Locations: ${ctx.locations.join(", ")}` : `Locations: ${MISSING_FACT}`,
    "",
    "### Customer problems",
    list(ctx.customerProblems, "- unknown"),
    "",
    "### Pain points",
    list(ctx.painPoints, "- unknown"),
    "",
    "### Business impact",
    list(ctx.businessImpact, "- unknown"),
    "",
    "### Differentiators",
    list(ctx.differentiators, "- unknown"),
    "",
    "### Benefits",
    list(ctx.benefits, "- unknown"),
    "",
    "### Website claims (not independently verified)",
    list(ctx.websiteClaims, "- none found"),
    "",
    "### Verified claims",
    list(ctx.verifiedClaims, "- none provided — use educational or hypothetical language"),
    "",
    "### Missing information",
    ctx.missingInformation.length
      ? ctx.missingInformation.map((m) => `- ${m}`).join("\n")
      : "- none flagged",
    "",
    "Rules: Do not invent company facts. If a field is missing or unknown, leave it out or say it is unknown. Do not fabricate customer results.",
  ].join("\n");
}
