"use client";

import { Suspense, useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { useForm, type FieldErrors, type Resolver } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { toast } from "sonner";
import { customerApi } from "@/lib/api/customer";
import { ApiException } from "@/lib/api/client";
import { useToken } from "@/lib/auth/useToken";
import { useAuth } from "@/lib/auth/AuthContext";
import Loader from "@/components/ui/Loader";
import SellerStepper from "./SellerStepper";
import StepBusinessInfo from "./StepBusinessInfo";
import StepContact from "./StepContact";
import StepDocuments from "./StepDocuments";
import StepBank from "./StepBank";
import StepProducts from "./StepProducts";
import StepReview from "./StepReview";
import SellerNavigation from "./SellerNavigation";
import {
  sellerWizardSchema,
  defaultSellerWizardValues,
  stepFieldMap,
  sellerSteps,
  type SellerWizardValues,
} from "./seller.schema";

type SellerRequestPayload = {
  request_reference?: string | null;
  request_status?: "draft" | "pending_review" | "approved" | "rejected";
  current_step?: number;
  can_edit?: boolean;
  submitted_at?: string | null;
  reviewed_at?: string | null;
  review_note?: string | null;
  timeline?: Array<Record<string, unknown>>;
  data?: Partial<SellerWizardValues> & Record<string, unknown>;
} | null;


/**
 * API record -> form values.
 *
 * Every text field goes through `toText`: the API returns `null` for anything
 * the applicant has not filled in yet, and spreading those straight into the
 * form left null where zod expects a string. Resuming a half-finished
 * application and submitting it then failed validation on fields the applicant
 * could see were filled in.
 */
function mapRequestToForm(payload: SellerRequestPayload): SellerWizardValues {
  const data = (payload?.data ?? {}) as Record<string, unknown>;
  const text = (key: string, fallback = "") => {
    const value = data[key];
    return value === null || value === undefined || value === "" ? fallback : String(value);
  };

  return {
    ...defaultSellerWizardValues,
    name: text("contact_person"),
    email: text("email"),

    company_name: text("company_name"),
    gst_number: text("gst_number"),
    pan_number: text("pan_number"),
    company_address: text("company_address"),
    seller_type: text("seller_type_id", text("seller_type")),
    constitution_type: text("constitution_type"),
    years_in_business: text("years_in_business"),
    city: text("city"),
    state: text("state"),
    country: text("country", "India"),
    pincode: text("pincode"),

    contact_person: text("contact_person"),
    designation: text("designation"),
    mobile: text("mobile"),
    alternate_mobile: text("alternate_mobile"),

    account_holder_name: text("account_holder_name"),
    bank_name: text("bank_name"),
    account_number: text("account_number"),
    ifsc_code: text("ifsc_code"),
    account_type: text("account_type"),
    branch: text("branch"),

    category: text("category"),
    products: text("products"),
    turnover: text("turnover"),
    product_upload_mode:
      text("product_upload_mode", "existing") === "bulk"
        ? "bulk"
        : text("product_upload_mode", "existing") === "new"
          ? "new"
          : "existing",

    /* Files are never round-tripped; what is already on file is tracked
       separately by `readSavedDocuments`. */
    gst_certificate: null,
    pan_document: null,
    registration_certificate: null,
    address_proof: null,
    cancelled_cheque: null,
    other_documents: null,
    product_sheet: null,
  };
}

/**
 * What the API says is already on file.
 *
 * The form fields themselves only ever hold a freshly picked `File`, so after a
 * step is saved and the form re-seeded they read as empty — which is why the
 * review step used to report documents the applicant had already uploaded as
 * "Not uploaded". These URLs are kept alongside the form and consulted instead.
 */
export type SavedDocuments = Partial<Record<SellerDocumentField, string>>;

export type SellerDocumentField =
  | "gst_certificate"
  | "pan_document"
  | "registration_certificate"
  | "address_proof"
  | "cancelled_cheque"
  | "other_documents"
  | "product_sheet";

const DOCUMENT_FIELDS: SellerDocumentField[] = [
  "gst_certificate",
  "pan_document",
  "registration_certificate",
  "address_proof",
  "cancelled_cheque",
  "other_documents",
  "product_sheet",
];

function readSavedDocuments(payload: SellerRequestPayload): SavedDocuments {
  const data = (payload?.data ?? {}) as Record<string, unknown>;
  const saved: SavedDocuments = {};
  for (const field of DOCUMENT_FIELDS) {
    const value = data[field];
    if (typeof value === "string" && value.trim()) saved[field] = value;
  }
  return saved;
}

export default function ProfilePage() {
  return (
    <Suspense fallback={<div className="rounded-xl bg-white p-10 shadow-sm ring-1 ring-gray-100"><Loader label="Loading profile…" /></div>}>
      <ProfilePageInner />
    </Suspense>
  );
}

function ProfilePageInner() {
  const router = useRouter();
  const { token, ready } = useToken();
  const { user } = useAuth();
  const [loadingProfile, setLoadingProfile] = useState(true);
  const [saving, setSaving] = useState(false);
  const [sellerTypes, setSellerTypes] = useState<{ id: number; name: string }[]>([]);
  const [requestPayload, setRequestPayload] = useState<SellerRequestPayload>(null);
  const [step, setStep] = useState(1);
  const [msg, setMsg] = useState<string | null>(null);
  const [apiErrors, setApiErrors] = useState<Record<string, string[]>>({});
  const [savedDocuments, setSavedDocuments] = useState<SavedDocuments>({});

  const form = useForm<SellerWizardValues>({
    // zod v4 preprocess widens the resolver's input type; cast to the output shape.
    resolver: zodResolver(sellerWizardSchema) as unknown as Resolver<SellerWizardValues>,
    defaultValues: defaultSellerWizardValues,
    mode: "onTouched",
  });

  const {
    handleSubmit,
    trigger,
    reset,
    setError,
    getValues,
    formState: { errors },
  } = form;

  const canEdit = requestPayload?.can_edit ?? true;
  const requestStatus = requestPayload?.request_status ?? "draft";
  const isSubmitted = requestStatus === "pending_review" || requestStatus === "approved";

  /* "pending_review" is the API's word for it; the applicant is told what it
     means for them. */
  const requestStatusLabel =
    requestStatus === "pending_review"
      ? "Submitted and under review"
      : requestStatus === "approved"
        ? "Approved"
        : requestStatus === "rejected"
          ? "Changes requested"
          : "Draft";

  useEffect(() => {
    if (!ready || !token) return;
    if (user?.type === "seller") {
      router.replace("/profile");
      return;
    }

    Promise.all([
      customerApi.sellerTypes(token),
      customerApi.sellerRequest(token).catch(() => null),
    ])
      .then(([types, request]) => {
        setSellerTypes(types.data ?? []);
        setRequestPayload(request);
        setSavedDocuments(readSavedDocuments(request as SellerRequestPayload));
        const mapped = mapRequestToForm(request as SellerRequestPayload);
        reset(mapped);
        setStep(Math.max(1, Math.min(6, Number(request?.current_step ?? 1))));
      })
      .finally(() => setLoadingProfile(false));
  }, [ready, token, user?.type, router, reset]);

  const nextStep = async () => {
    if (!token || !canEdit) return;
    const fields = stepFieldMap[step - 1] ?? [];
    const valid = fields.length ? await trigger(fields) : true;
    if (!valid) return;
    await persistStep(step);
    setStep((prev) => Math.min(prev + 1, 6));
  };

  const prevStep = () => setStep((prev) => Math.max(prev - 1, 1));

  const handleInvalidSubmit = (fieldErrors: FieldErrors<SellerWizardValues>) => {
    const firstField = Object.keys(fieldErrors)[0] as keyof SellerWizardValues | undefined;

    if (firstField) {
      const targetStep = stepFieldMap.findIndex((fields) => fields.includes(firstField)) + 1;
      if (targetStep > 0) {
        setStep(targetStep);
      }

      const message = fieldErrors[firstField]?.message;
      const label = firstField.replace(/_/g, " ");
      toast.error(typeof message === "string" && message ? `${label}: ${message}` : `Please fix ${label} before submitting.`);
      return;
    }

    toast.error("Please fix the highlighted fields before submitting.");
  };

  const persistStep = async (currentStep: number) => {
    if (!token || !canEdit) return;
    const values = getValues();
    setSaving(true);
    setMsg(null);
    setApiErrors({});
    try {
      const payload = buildSellerPayload(values, sellerTypes);
      payload.append("step", String(currentStep));
      await customerApi.saveSellerRequestStep(token, payload);
      const fresh = await customerApi.sellerRequest(token).catch(() => null);
      setRequestPayload(fresh);
      setSavedDocuments(readSavedDocuments(fresh));
      if (fresh) reset(mapRequestToForm(fresh));
      setMsg(null);
      toast.success(`${sellerSteps[currentStep - 1]} saved successfully.`);
    } catch (err) {
      if (err instanceof ApiException) {
        setApiErrors(err.errors ?? {});
        Object.entries(err.errors ?? {}).forEach(([field, messages]) => {
          const first = messages?.[0];
          if (first) setError(field as keyof SellerWizardValues, { type: "server", message: first });
        });
        setMsg(err.message);
      } else {
        setMsg("Step save failed");
      }
    } finally {
      setSaving(false);
    }
  };

  const submit = async (values: SellerWizardValues) => {
    if (!token || !canEdit) return;
    setSaving(true);
    setApiErrors({});
    setMsg(null);
    try {
      const payload = buildSellerPayload(values, sellerTypes);
      const response = await customerApi.submitSellerRequest(token, payload);
      const fresh = await customerApi.sellerRequest(token).catch(() => response.data as SellerRequestPayload);
      setRequestPayload(fresh);
      setSavedDocuments(readSavedDocuments(fresh));
      setMsg(null);
      toast.success(response.message || "Seller request submitted successfully.");
      reset(mapRequestToForm(fresh));
    } catch (err) {
      if (err instanceof ApiException) {
        setApiErrors(err.errors ?? {});
        Object.entries(err.errors ?? {}).forEach(([field, messages]) => {
          const first = messages?.[0];
          if (first) setError(field as keyof SellerWizardValues, { type: "server", message: first });
        });
        const firstServerMessage = Object.values(err.errors ?? {}).flat().find(Boolean);
        const userMessage = firstServerMessage || err.message || "Submission failed";
        setMsg(userMessage);
        toast.error(userMessage);
      } else {
        setMsg("Submission failed");
        toast.error("Submission failed");
      }
    } finally {
      setSaving(false);
    }
  };

  const heading = useMemo(() => "Become a Seller", []);
  const currentStepDescription = useMemo(
    () => [
      "Please provide your business information.",
      "Please provide your contact person details.",
      "Please upload your business documents.",
      "Please provide your bank account details.",
      "Please provide your store and product details.",
      "Review everything before submitting your request.",
    ][Math.max(0, Math.min(step - 1, 5))],
    [step]
  );

  if (loadingProfile) {
    return <div className="rounded-xl bg-white p-10 shadow-sm ring-1 ring-gray-100"><Loader label="Loading profile…" /></div>;
  }

  return (
    <div className="space-y-4">
      <div>
        <h1 className="text-xl font-semibold text-gray-900">{heading}</h1>
        <p className="mt-1 text-sm text-gray-600">Empowering suppliers, elevating success — more sales, less worries.</p>
      </div>

      <div className="rounded-2xl border border-slate-200 bg-white/95 p-4 shadow-[0_18px_40px_-28px_rgba(15,23,42,0.35)] backdrop-blur-sm sm:p-5 lg:p-6">
        <SellerStepper currentStep={step} allComplete={isSubmitted} />

        <div className="mt-5 rounded-xl border border-slate-200 bg-slate-50/90 px-4 py-3 shadow-[0_10px_26px_-24px_rgba(15,23,42,0.35)] sm:px-5 sm:py-4">
          <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
            <div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-slate-700">
              <span className="inline-flex items-center rounded-full bg-white px-2.5 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 ring-1 ring-slate-200">
                Step {step} of 6
              </span>
              <span className="text-slate-400">•</span>
              <span className="font-medium text-slate-600">{currentStepDescription}</span>
            </div>

            <div className="flex flex-wrap items-center gap-2 text-xs text-slate-500 sm:justify-end">
              <span className="rounded-full bg-white px-2.5 py-1 font-medium ring-1 ring-slate-200">
                Request Status: {requestStatusLabel}
              </span>
              {requestPayload?.request_reference ? (
                <span className="rounded-full bg-white px-2.5 py-1 font-medium ring-1 ring-slate-200">
                  Reference: {requestPayload.request_reference}
                </span>
              ) : null}
            </div>
          </div>
        </div>
      </div>

      <form onSubmit={handleSubmit(submit, handleInvalidSubmit)} className="space-y-4">
        {step === 1 && <StepBusinessInfo form={form} sellerTypes={sellerTypes} />}
        {step === 2 && <StepContact form={form} />}
        {step === 3 && <StepDocuments form={form} savedDocuments={savedDocuments} />}
        {step === 4 && <StepBank form={form} />}
        {step === 5 && <StepProducts form={form} savedDocuments={savedDocuments} />}
        {step === 6 && (
          <StepReview values={getValues()} sellerTypes={sellerTypes} savedDocuments={savedDocuments} />
        )}

        <SellerNavigation
          step={step}
          totalSteps={6}
          saving={saving}
          msg={msg}
          hasError={Boolean(Object.keys(errors).length || Object.keys(apiErrors).length || (msg && msg.toLowerCase().includes("fail")))}
          onPrev={prevStep}
          onNext={nextStep}
          locked={!canEdit}
          submitted={isSubmitted}
        />
      </form>
    </div>
  );
}

function buildSellerPayload(values: SellerWizardValues, sellerTypes: { id: number; name: string }[]) {
  const payload = new FormData();
  const selectedSellerType = sellerTypes.find((type) => String(type.id) === values.seller_type);

  payload.append("name", values.contact_person || values.name || "");
  payload.append("email", values.email || "");
  payload.append("company_name", values.company_name || "");
  payload.append("gst_number", values.gst_number || "");
  payload.append("company_address", values.company_address || "");
  payload.append("constitution_type", values.constitution_type || "");
  payload.append("years_in_business", values.years_in_business || "");
  payload.append("city", values.city || "");
  payload.append("state", values.state || "");
  payload.append("country", values.country || "");
  payload.append("pincode", values.pincode || "");
  payload.append("contact_person", values.contact_person || "");
  payload.append("designation", values.designation || "");
  payload.append("mobile", values.mobile || "");
  payload.append("alternate_mobile", values.alternate_mobile || "");
  payload.append("account_holder_name", values.account_holder_name || "");
  payload.append("bank_name", values.bank_name || "");
  payload.append("account_number", values.account_number || "");
  payload.append("ifsc_code", values.ifsc_code || "");
  payload.append("account_type", values.account_type || "");
  payload.append("branch", values.branch || "");
  payload.append("category", values.category || "");
  payload.append("products", values.products || "");
  payload.append("turnover", values.turnover || "");
  if (values.product_sheet instanceof File) payload.append("product_sheet", values.product_sheet);
  payload.append("product_upload_mode", values.product_upload_mode || "existing");
  payload.append("seller_type_id", values.seller_type || "");
  payload.append("business_type", selectedSellerType?.name || "");
  if (values.pan_number) payload.append("pan_number", values.pan_number);

  if (values.gst_certificate instanceof File) payload.append("gst_certificate", values.gst_certificate);
  if (values.pan_document instanceof File) payload.append("pan_document", values.pan_document);
  if (values.registration_certificate instanceof File) payload.append("registration_certificate", values.registration_certificate);
  if (values.address_proof instanceof File) payload.append("address_proof", values.address_proof);
  if (values.cancelled_cheque instanceof File) payload.append("cancelled_cheque", values.cancelled_cheque);
  if (values.other_documents instanceof File) payload.append("other_documents", values.other_documents);

  return payload;
}