"use client";

import { useRef, useState, useMemo } from "react";
import DOMPurify from "dompurify";
import { useSearchParams } from "next/navigation";
import { CheckCircle2, Lock, Plus, Receipt, Upload, X } from "lucide-react";
import { useMutation } from "@tanstack/react-query";
import { Container } from "@/components/common/Container";
import { Card, CardContent } from "@/components/common/Card";
import { Button } from "@/components/common/Button";
import { FormField } from "@/components/app/FormField";
import { sendRemittanceApi } from "@/api/sendRemittance.api";
import type { ManualInputField } from "@/api/sendRemittance.api";
import { useManualFields } from "@/hooks/queries/useSendRemittance";
import { useTranslation } from "@/hooks/useTranslation";
import { useKycGate } from "@/hooks/useKycGate";
import { KycGate } from "@/components/app/KycGate";
import { cn } from "@/lib/utils";

// Different gateways author instructions differently: some use real
// <ol>/<li> markup, others one <br>-joined blob with manually typed "1. ",
// "2. " prefixes instead of a list at all — unreadable as one wall of text
// either way once dropped straight into dangerouslySetInnerHTML. Flatten both
// shapes back into plain lines and regroup any run of list/numbered lines
// into its own block, so the UI can render real numbered steps regardless of
// source markup. Some sections (e.g. "Bank Transfer") list their steps with
// no leading digits or <li> at all — for those, any short line directly
// under a <strong>-only heading is treated as a step too, so it still
// renders as a numbered list instead of flat unformatted lines.
type DescBlock = { kind: "html"; html: string } | { kind: "steps"; items: string[] };

const HEADING_RE = /^<strong[^>]*>[^<]+<\/strong>:?$/i;
const STEP_MAX_LEN = 130;

function parseGatewayInstructions(raw: string): DescBlock[] {
  const flat = raw
    .replace(/<\/?(ol|ul)[^>]*>/gi, "\n")
    .replace(/<li[^>]*>/gi, "")
    .replace(/<\/li>/gi, "\n")
    .replace(/<\/p>\s*<p>/gi, "\n")
    .replace(/<br\s*\/?>/gi, "\n")
    .replace(/<\/?p>/gi, "");

  const lines = flat.split(/\n+/).map((l) => l.trim()).filter(Boolean);

  const blocks: DescBlock[] = [];
  let steps: string[] = [];
  const flushSteps = () => {
    if (steps.length === 0) return;
    blocks.push({ kind: "steps", items: steps });
    steps = [];
  };

  for (const line of lines) {
    const match = line.match(/^(\d+)\.\s*(.+)$/);
    if (match) {
      steps.push(match[2]);
      continue;
    }
    if (HEADING_RE.test(line)) {
      flushSteps();
      blocks.push({ kind: "html", html: line });
      continue;
    }
    if (line.length <= STEP_MAX_LEN) {
      steps.push(line);
      continue;
    }
    flushSteps();
    blocks.push({ kind: "html", html: line });
  }
  flushSteps();

  return blocks;
}

export default function SendManualView() {
  const { t } = useTranslation();
  const kycGateStatus = useKycGate();
  const searchParams = useSearchParams();
  const identifier = searchParams.get("identifier") ?? "";
  const alias = searchParams.get("alias") ?? "";

  const { data, isLoading } = useManualFields(alias);
  const fields = data?.input_fields ?? [];

  const descBlocks = useMemo((): DescBlock[] => {
    if (typeof window === "undefined" || !data?.gateway.desc) return [];
    return parseGatewayInstructions(data.gateway.desc).map((block) =>
      block.kind === "html"
        ? { kind: "html", html: DOMPurify.sanitize(block.html, { FORBID_ATTR: ["style"] }) }
        : {
            kind: "steps",
            items: block.items.map((item) => DOMPurify.sanitize(item, { FORBID_ATTR: ["style"] })),
          },
    );
  }, [data]);
  const hasInstructions = descBlocks.length > 0;

  const [textValues, setTextValues] = useState<Record<string, string>>({});
  const [fileValues, setFileValues] = useState<Record<string, File[]>>({});
  const [filePreviews, setFilePreviews] = useState<Record<string, string[]>>({});
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
  const fileRefs = useRef<Record<string, HTMLInputElement | null>>({});

  const mutation = useMutation({
    mutationFn: () => {
      const input: Record<string, string | File | File[]> = { identifier };
      for (const field of fields) {
        if (field.type === "file") {
          const files = fileValues[field.name] ?? [];
          if (files.length > 0) {
            input[field.name] = files.length === 1 ? files[0] : files;
          }
        } else {
          input[field.name] = textValues[field.name] ?? "";
        }
      }
      return sendRemittanceApi.submitManual(
        input as Parameters<typeof sendRemittanceApi.submitManual>[0],
      );
    },
  });

  function handleFilesChange(field: ManualInputField, incoming: FileList | null) {
    if (!incoming || incoming.length === 0) return;
    const mimes = field.validation.mimes.map((m) => m.trim().toLowerCase());
    const maxMb = parseFloat(String(field.validation.max)) || 10;
    const valid: File[] = [];

    for (const file of Array.from(incoming)) {
      const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
      if (mimes.length && !mimes.includes(ext)) {
        setFieldErrors((prev) => ({
          ...prev,
          [field.name]: t("app.send.manual.allowedFormats").replace("{formats}", mimes.join(", ")),
        }));
        continue;
      }
      if (file.size > maxMb * 1024 * 1024) {
        setFieldErrors((prev) => ({
          ...prev,
          [field.name]: t("app.send.manual.maxSize").replace("{size}", String(maxMb)),
        }));
        continue;
      }
      valid.push(file);
    }

    if (valid.length === 0) return;
    setFieldErrors((prev) => { const n = { ...prev }; delete n[field.name]; return n; });
    setFileValues((prev) => ({ ...prev, [field.name]: [...(prev[field.name] ?? []), ...valid] }));
    setFilePreviews((prev) => ({
      ...prev,
      [field.name]: [...(prev[field.name] ?? []), ...valid.map((f) => URL.createObjectURL(f))],
    }));
    if (fileRefs.current[field.name]) fileRefs.current[field.name]!.value = "";
  }

  function removeFile(fieldName: string, idx: number) {
    setFileValues((prev) => {
      const files = [...(prev[fieldName] ?? [])];
      files.splice(idx, 1);
      return { ...prev, [fieldName]: files };
    });
    setFilePreviews((prev) => {
      const previews = [...(prev[fieldName] ?? [])];
      URL.revokeObjectURL(previews[idx]);
      previews.splice(idx, 1);
      return { ...prev, [fieldName]: previews };
    });
  }

  function validate(): boolean {
    const e: Record<string, string> = {};
    for (const field of fields) {
      if (field.type === "file") {
        if (field.required && (fileValues[field.name] ?? []).length === 0) {
          e[field.name] = t("app.send.manual.fieldRequired").replace("{label}", field.label);
        }
      } else {
        const val = textValues[field.name]?.trim() ?? "";
        if (field.required && !val) {
          e[field.name] = t("app.send.manual.fieldRequired").replace("{label}", field.label);
        }
        const min = parseInt(String(field.validation.min), 10);
        if (!isNaN(min) && min > 0 && val.length < min) {
          e[field.name] = t("app.send.manual.minLength")
            .replace("{label}", field.label)
            .replace("{min}", String(min));
        }
      }
    }
    setFieldErrors(e);
    return Object.keys(e).length === 0;
  }

  function onSubmit(e: { preventDefault(): void }) {
    e.preventDefault();
    if (!validate()) return;
    mutation.mutate();
  }

  if (mutation.isSuccess) {
    return (
      <Container className="max-w-lg">
        <Card>
          <CardContent>
            <div className="py-6 text-center">
              <span className="mx-auto grid h-16 w-16 place-items-center rounded-2xl bg-gradient-to-br from-accent-100 to-accent-50 text-accent-600 dark:from-accent-500/25 dark:to-accent-500/5 dark:text-accent-300">
                <CheckCircle2 className="h-8 w-8" />
              </span>
              <h2 className="mt-5 text-[length:var(--text-lg-fixed)] font-bold text-slate-900 dark:text-white">
                {t("app.send.manual.successTitle")}
              </h2>
              <p className="mt-2 text-sm text-slate-500 dark:text-slate-400">
                {t("app.send.manual.successBody")}
              </p>
            </div>
          </CardContent>
        </Card>
      </Container>
    );
  }

  if (kycGateStatus) {
    return <KycGate status={kycGateStatus} />;
  }

  return (
    <Container className="max-w-full space-y-5">
      <div className="flex items-center gap-4">
        <span className="grid h-14 w-14 shrink-0 place-items-center rounded-2xl bg-gradient-to-br from-brand-600 to-brand-500 text-white shadow-soft">
          <Receipt className="h-7 w-7" />
        </span>
        <div>
          <h1 className="text-[length:var(--text-2xl)] font-bold text-slate-900 dark:text-white">
            {t("app.send.manual.title")}
          </h1>
          <p className="text-sm text-slate-500 dark:text-slate-400">
            {t("app.send.manual.subtitle")}
          </p>
        </div>
      </div>

      {isLoading ? (
        <div className="grid gap-5 xl:grid-cols-[minmax(0,1fr)_minmax(0,1.35fr)] xl:items-start">
          <Card>
            <CardContent>
              <div className="space-y-3">
                {[1, 2, 3].map((i) => (
                  <div key={i} className="h-5 animate-pulse rounded-lg bg-slate-200 dark:bg-slate-700" />
                ))}
              </div>
            </CardContent>
          </Card>
          <Card>
            <CardContent>
              <div className="space-y-5">
                {[1, 2, 3].map((i) => (
                  <div key={i} className="h-11 animate-pulse rounded-2xl bg-slate-200 dark:bg-slate-700" />
                ))}
              </div>
            </CardContent>
          </Card>
        </div>
      ) : (
        <div
          className={cn(
            hasInstructions && "xl:grid xl:grid-cols-[minmax(0,1fr)_minmax(0,1.35fr)] xl:items-start xl:gap-5",
          )}
        >
          {hasInstructions && (
            <Card className="xl:sticky xl:top-6">
              <CardContent>
                <div className="mb-4">
                  <h2 className="text-[length:var(--text-lg-fixed)] font-bold text-slate-900 dark:text-white">
                    {t("app.send.manual.instructionsTitle")}
                  </h2>
                </div>
                <div className="space-y-4">
                  {descBlocks.map((block, blockIdx) =>
                    block.kind === "steps" ? (
                      <ol key={blockIdx} className="list-decimal space-y-1.5 ps-5 marker:font-semibold marker:text-slate-500 dark:marker:text-slate-400">
                        {block.items.map((item, idx) => (
                          <li
                            key={idx}
                            className="text-sm leading-relaxed text-slate-700 dark:text-slate-300"
                            dangerouslySetInnerHTML={{ __html: item }}
                          />
                        ))}
                      </ol>
                    ) : (
                      <div
                        key={blockIdx}
                        className="prose prose-sm max-w-none text-slate-700 dark:text-slate-300 [&_p]:mb-0 [&_p]:leading-relaxed [&_strong]:font-semibold [&_strong]:text-slate-900 dark:[&_strong]:text-white"
                        dangerouslySetInnerHTML={{ __html: block.html }}
                      />
                    ),
                  )}
                </div>
              </CardContent>
            </Card>
          )}

          <Card className={hasInstructions ? "mt-5 xl:mt-0" : undefined}>
            <CardContent>
              <div className="mb-5">
                <h2 className="text-[length:var(--text-lg-fixed)] font-bold text-slate-900 dark:text-white">
                  {t("app.send.manual.detailsTitle")}
                </h2>
                <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
                  {t("app.send.manual.detailsSubtitle")}
                </p>
              </div>
              <form onSubmit={onSubmit} noValidate className="space-y-5">
                {fields.map((field) => {
                  if (field.type === "file") {
                    const previews = filePreviews[field.name] ?? [];
                    const files = fileValues[field.name] ?? [];
                    const mimes = field.validation.mimes.map((m) => m.trim());
                    return (
                      <div key={field.name} className="space-y-1.5">
                        <label className="block text-[length:var(--text-sm-fixed)] font-semibold capitalize tracking-wider text-slate-500 dark:text-slate-400">
                          {field.label}
                          {field.required && <span className="ms-1 text-rose-500">*</span>}
                        </label>

                        {previews.length > 0 && (
                          <div className="grid grid-cols-3 gap-2 sm:grid-cols-4">
                            {previews.map((src, idx) => (
                              <div
                                key={idx}
                                className="relative aspect-square overflow-hidden rounded-xl border border-slate-200 dark:border-slate-700"
                              >
                                <img
                                  src={src}
                                  alt={t("app.send.manual.filePreviewAlt").replace("{n}", String(idx + 1))}
                                  className="h-full w-full object-cover"
                                />
                                <button
                                  type="button"
                                  onClick={() => removeFile(field.name, idx)}
                                  className="absolute end-1 top-1 grid h-5 w-5 place-items-center rounded-full bg-black/60 text-white transition hover:bg-black/80"
                                >
                                  <X className="h-3 w-3" />
                                </button>
                              </div>
                            ))}

                            <label
                              className={cn(
                                "flex aspect-square cursor-pointer flex-col items-center justify-center gap-1 rounded-xl border-2 border-dashed border-slate-200 text-slate-400 transition hover:border-brand-400 hover:text-brand-500 dark:border-slate-700",
                              )}
                            >
                              <Plus className="h-5 w-5" />
                              <span className="text-xs">{t("app.send.manual.addFile")}</span>
                              <input
                                ref={(el) => { fileRefs.current[field.name] = el; }}
                                type="file"
                                multiple
                                className="sr-only"
                                accept={mimes.map((m) => `.${m}`).join(",")}
                                onChange={(e) => handleFilesChange(field, e.target.files)}
                              />
                            </label>
                          </div>
                        )}

                        {previews.length === 0 && (
                          <label
                            className="flex min-h-40 cursor-pointer flex-col items-center justify-center gap-3 rounded-2xl border-2 border-dashed border-slate-200 text-slate-400 transition hover:border-brand-400 hover:text-brand-500 dark:border-slate-700"
                          >
                            <span className="grid h-12 w-12 place-items-center rounded-full bg-slate-100 dark:bg-slate-800">
                              <Upload className="h-5 w-5" />
                            </span>
                            <div className="text-center">
                              <p className="text-sm text-slate-600 dark:text-slate-300">
                                {t("app.send.manual.dragDrop")}
                              </p>
                              <p className="mt-0.5 text-sm">
                                {t("app.send.manual.or")}{" "}
                                <span className="font-semibold text-brand-600 dark:text-brand-400">
                                  {t("app.send.manual.clickToBrowse")}
                                </span>
                              </p>
                              {mimes.length > 0 && (
                                <p className="mt-2 text-xs">
                                  {t("app.send.manual.uploadFormats").replace("{formats}", mimes.join(", "))}
                                </p>
                              )}
                            </div>
                            <input
                              ref={(el) => { fileRefs.current[field.name] = el; }}
                              type="file"
                              multiple
                              className="sr-only"
                              accept={mimes.map((m) => `.${m}`).join(",")}
                              onChange={(e) => handleFilesChange(field, e.target.files)}
                            />
                          </label>
                        )}

                        {files.length > 0 && (
                          <p className="text-xs text-slate-500 dark:text-slate-400">
                            {t("app.send.manual.filesSelected")
                              .replace("{n}", String(files.length))
                              .replace("{s}", files.length !== 1 ? "s" : "")}
                          </p>
                        )}
                        {fieldErrors[field.name] && (
                          <p className="text-xs font-medium text-rose-600">
                            {fieldErrors[field.name]}
                          </p>
                        )}
                      </div>
                    );
                  }

                  return (
                    <div key={field.name} className="space-y-1.5">
                      <FormField
                        label={field.label}
                        placeholder={`Enter ${field.label.toLowerCase()}`}
                        value={textValues[field.name] ?? ""}
                        onChange={(e) =>
                          setTextValues((prev) => ({ ...prev, [field.name]: e.target.value }))
                        }
                        required={field.required}
                      />
                      {fieldErrors[field.name] && (
                        <p className="text-xs font-medium text-rose-600">
                          {fieldErrors[field.name]}
                        </p>
                      )}
                    </div>
                  );
                })}

                {mutation.isError && (
                  <p className="text-xs font-medium text-rose-600">
                    {t("app.send.manual.submitFailed")}
                  </p>
                )}

                <Button
                  type="submit"
                  size="lg"
                  loading={mutation.isPending}
                  disabled={mutation.isPending}
                  className="w-full font-medium"
                >
                  {!mutation.isPending && <Lock className="h-4 w-4" aria-hidden />}
                  {t("app.send.manual.submit")}
                </Button>
              </form>
            </CardContent>
          </Card>
        </div>
      )}
    </Container>
  );
}
