"use client"

import { useRouter } from "next/navigation"
import { zodResolver } from "@hookform/resolvers/zod"
import type { LucideIcon } from "lucide-react"
import * as React from "react"
import { Controller, useForm } from "react-hook-form"
import { toast } from "sonner"
import type { ZodType } from "zod"

import {
  FormPageHeader,
  FormPanel,
  FormSaveBar,
} from "@/app/dashboard/_components/form"
import { Field, FieldError, FieldLabel } from "@/components/ui/field"
import { XML_API_BANK_NAME_OPTIONS } from "@/components/xml-apis/shared/bank-name-options"
import { XmlFileDropzone } from "@/components/xml-apis/shared/xml-file-dropzone"
import {
  validateXmlFiles,
  XML_UPLOAD_MAX_FILES,
  XML_UPLOAD_MAX_FILE_SIZE_MB,
} from "@/components/xml-apis/shared/xml-upload-validation"
import { SettingsSelect } from "@/components/settings/ui/settings-select"

/**
 * Common shape every "select a bank, upload XML files" create form shares.
 * A form with extra fields (e.g. account-xml-upload) needs its own extension
 * point rather than forcing this factory's fields/validation to generalize.
 */
export type XmlUploadCreateFormValues = {
  bankName: string
  fileName: string
  fileCount: number
}

export type XmlUploadCreateFormConfig = {
  icon: LucideIcon
  /** Breadcrumb label and page-list link text, e.g. "Asset XML Upload". */
  entityLabel: string
  title: string
  description: string
  successMessage: string
  listHref: string
  schema: ZodType<XmlUploadCreateFormValues, XmlUploadCreateFormValues>
  onCreate: (values: XmlUploadCreateFormValues, files: File[]) => Promise<void>
  /** Restrict the dropzone to exactly one file (e.g. account-xml-upload). */
  single?: boolean
  /** Overrides the dropzone's default "Browse XML files" label. */
  browseLabel?: string
  /** Optional label rendered above the dropzone (omitted by default). */
  fileFieldLabel?: string
}

const DEFAULT_VALUES: XmlUploadCreateFormValues = {
  bankName: "please-select",
  fileName: "",
  fileCount: 0,
}

/**
 * Factory for the "select a bank, drop XML files, submit" create-form pattern
 * shared by asset/xrate XML upload. Mirrors createXmlApiPaginatedListHook's
 * factory approach one layer up, in the presentation layer.
 */
export function createXmlUploadCreateForm(config: XmlUploadCreateFormConfig) {
  return function XmlUploadCreateForm() {
    const router = useRouter()
    const [fileNames, setFileNames] = React.useState<string[]>([])
    const [selectedFiles, setSelectedFiles] = React.useState<File[]>([])
    const [fileError, setFileError] = React.useState<string | null>(null)

    const form = useForm<XmlUploadCreateFormValues>({
      resolver: zodResolver(config.schema),
      defaultValues: DEFAULT_VALUES,
      mode: "onBlur",
    })

    const {
      control,
      handleSubmit,
      setValue,
      formState: { errors, isSubmitting },
    } = form

    const bankNameError = errors.bankName?.message
    const fileNameError = errors.fileName?.message
    const fileCountError = errors.fileCount?.message

    const applyFiles = (files: File[]) => {
      const validationError = validateXmlFiles(files, { single: config.single })
      if (validationError) {
        setFileError(validationError)
        setFileNames([])
        setSelectedFiles([])
        setValue("fileName", "", { shouldValidate: true })
        setValue("fileCount", 0, { shouldValidate: true })
        return
      }
      setFileError(null)
      const names = files.map((f) => f.name)
      setFileNames(names)
      setSelectedFiles(files)
      setValue("fileName", names[0] ?? "", { shouldValidate: true })
      setValue("fileCount", names.length, { shouldValidate: true })
    }

    const onSubmit = handleSubmit(async (values) => {
      try {
        await config.onCreate(values, selectedFiles)
        toast.success(config.successMessage)
        router.push(config.listHref)
      } catch {
        toast.error("Failed to save")
      }
    })

    return (
      <form onSubmit={(e) => void onSubmit(e)} className="pb-4">
        <FormPageHeader
          backHref={config.listHref}
          breadcrumb={[
            { label: "XML API" },
            { label: config.entityLabel, href: config.listHref },
            { label: "Create new" },
          ]}
          titleIcon={<config.icon className="size-5 text-primary" />}
          title={config.title}
          description={config.description}
        />

        <FormPanel title="Upload details">
          <div className="space-y-6">
            <Field data-invalid={!!bankNameError} className="max-w-md gap-1.5">
              <FieldLabel className="text-sm font-medium">
                Bank name <span className="text-destructive">*</span>
              </FieldLabel>
              <Controller
                name="bankName"
                control={control}
                render={({ field }) => (
                  <SettingsSelect
                    value={field.value}
                    onValueChange={field.onChange}
                    options={XML_API_BANK_NAME_OPTIONS}
                    placeholder="Please select"
                  />
                )}
              />
              <FieldError
                errors={bankNameError ? [{ message: String(bankNameError) }] : undefined}
              />
            </Field>

            <Field
              data-invalid={!!fileNameError || !!fileCountError || !!fileError}
              className="gap-1.5"
            >
              {config.fileFieldLabel ? (
                <FieldLabel className="text-sm font-medium">
                  {config.fileFieldLabel} <span className="text-destructive">*</span>
                </FieldLabel>
              ) : null}
              <XmlFileDropzone
                multiple={!config.single}
                browseLabel={config.browseLabel}
                onFilesChosen={applyFiles}
                onFilesSelected={() => {}}
              />
              {fileNames.length > 0 ? (
                <ul className="text-sm text-muted-foreground">
                  {fileNames.map((n) => (
                    <li key={n}>{n}</li>
                  ))}
                </ul>
              ) : null}
              {config.single ? null : (
                <p className="text-xs text-muted-foreground">
                  XML only · max {XML_UPLOAD_MAX_FILES} files · {XML_UPLOAD_MAX_FILE_SIZE_MB}MB per
                  file
                </p>
              )}
              <FieldError
                errors={
                  fileError || fileNameError || fileCountError
                    ? [
                        {
                          message: String(fileError ?? fileNameError ?? fileCountError),
                        },
                      ]
                    : undefined
                }
              />
            </Field>
          </div>
        </FormPanel>

        <FormSaveBar
          cancelHref={config.listHref}
          isSaving={isSubmitting}
          saveLabel="Save changes"
          onReset={() => {
            form.reset(DEFAULT_VALUES)
            setFileNames([])
            setSelectedFiles([])
            setFileError(null)
          }}
        />
      </form>
    )
  }
}
