"use client"

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { MultiSelect } from "@/components/ui/multi-select"
import { Textarea } from "@/components/ui/textarea"
import {
  cabSchema,
  foodSchema,
  hotelSchema,
  otherSchema,
} from "@/lib/validations"
import { createHotel, updateHotel } from "@/services/hotels"
import { zodResolver } from "@hookform/resolvers/zod"
import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { z } from "zod"

import {
  FileUpload,
  FileUploadDropzone,
  FileUploadItem,
  FileUploadItemMetadata,
  FileUploadItemPreview,
  FileUploadList
} from "@/components/ui/file-upload"
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { RichTextEditor } from "@/components/ui/rich-text-editor"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import { PlusIcon, TrashIcon, X } from "lucide-react"
import React from "react"

// Define the type for the fields we pass from the server
interface EntityFormProps {
  entity: string
  fields: any[]
  values?: Record<string, any> // Add this line to accept values for editing
}

export function EntityForm({ entity, fields, values }: EntityFormProps) {
  const router = useRouter()

  const [mainImage, setMainImage] = React.useState<any[]>([])
  const [gallery, setGallery] = React.useState<any[]>([])
  const [deletedGallery, setDeletedGallery] = React.useState<any[]>([])
  const [deletedMainImage, setDeletedMainImage] = React.useState<any[]>([])
  const [roomPricing, setRoomPricing] = React.useState<any[]>(
    values?.room_pricing || [
      {
        room_count: 1,
        days_count: 1,
        price: 0,
      },
    ]
  )

  React.useEffect(() => {
    if (values?.main_image) {
      setMainImage([values.main_image])
    }

    if (values?.gallery) {
      const galleryImages =
        typeof values.gallery === "string"
          ? JSON.parse(values.gallery)
          : values.gallery || []

      setGallery(galleryImages)
    }
  }, [values])

  const defaultValues = fields.reduce(
    (acc, field) => {
      const fieldValue = values?.[field.name]

      if (field.type === "gallery") {
        acc[field.name] = Array.isArray(fieldValue) ? fieldValue : []
      } else if (field.type === "file") {
        acc[field.name] = fieldValue ?? null
      } else if (field.type === "multiselect") {
        if (Array.isArray(fieldValue)) {
          acc[field.name] = fieldValue
        } else if (
          typeof fieldValue === "string" &&
          fieldValue.trim().startsWith("[")
        ) {
          try {
            acc[field.name] = JSON.parse(fieldValue)
          } catch {
            acc[field.name] = []
          }
        } else if (typeof fieldValue === "string" && fieldValue.includes(",")) {
          acc[field.name] = fieldValue
            .split(",")
            .map((item) => item.trim())
            .filter(Boolean)
        } else if (fieldValue !== undefined && fieldValue !== null) {
          acc[field.name] = [String(fieldValue)]
        } else {
          acc[field.name] = []
        }
      } else {
        acc[field.name] = fieldValue ?? ""
      }

      return acc
    },
    {} as Record<string, any>
  )

  let form: any, FormSchema: any

  const dynamicFields: Record<string, any> = {}
  const baseSchemaFields =
    entity === "hotels"
      ? Object.keys(hotelSchema.shape)
      : entity === "cabs"
        ? Object.keys(cabSchema.shape)
        : entity === "foods"
          ? Object.keys(foodSchema.shape)
          : Object.keys(otherSchema.shape)

  fields.forEach((field) => {
    // Skip fields already present in base schema
    if (baseSchemaFields.includes(field.name)) {
      return
    }

    let validator

    switch (field.type) {
      case "number":
        validator = z.coerce.number()

        if (field.is_required) {
          validator = validator.min(1, `${field.label} is required`)
        } else {
          validator = validator.optional()
        }

        break

      case "multiselect":
        validator = z.array(z.string())

        if (field.is_required) {
          validator = validator.min(1, `${field.label} is required`)
        } else {
          validator = validator.optional()
        }

        break

      case "file":
        validator = z.any().optional()
        break

      case "gallery":
        validator = z.array(z.any()).optional()
        break

      case "room_pricing":
        validator = z
          .array(
            z.object({
              room_count: z.coerce.number().min(1, "Rooms required"),
              days_count: z.coerce.number().min(1, "Days required"),
              price: z.coerce.number().min(1, "Price required"),
            })
          )
          .optional()

        break
      case "richtext":
        validator = z.string()

        if (field.is_required) {
          validator = validator.min(1, `${field.label} is required`)
        } else {
          validator = validator.optional()
        }

        break

      default:
        validator = z.string()

        if (field.is_required) {
          validator = validator.min(1, `${field.label} is required`)
        } else {
          validator = validator.optional()
        }
    }

    dynamicFields[field.name] = validator
  })

  let dynamicSchema: any

  switch (entity) {
    case "hotels":
      dynamicSchema = hotelSchema.extend(dynamicFields)
      FormSchema = hotelSchema
      break
    case "cabs":
      dynamicSchema = cabSchema.extend(dynamicFields)
      FormSchema = cabSchema
      break
    case "foods":
      dynamicSchema = foodSchema.extend(dynamicFields)
      FormSchema = foodSchema
      break
    case "others":
      dynamicSchema = otherSchema.extend(dynamicFields)
      FormSchema = otherSchema
      break
    default:
      null
      break
  }

  const fieldRefs = React.useRef<Record<string, HTMLDivElement | null>>({})
  const onError = (errors: any) => {
    const onError = (errors: any) => {
      const firstErrorKey = Object.keys(errors)[0]

      if (!firstErrorKey) return

      const element = fieldRefs.current[firstErrorKey]

      if (element) {
        element.scrollIntoView({
          behavior: "smooth",
          block: "center",
        })

        // focus input/select/textarea inside wrapper
        const input = element.querySelector(
          "input, textarea, button, [contenteditable='true']"
        ) as HTMLElement

        input?.focus()
      }

      toast.error("Please fix validation errors")
    }
  }

  form = useForm({
    resolver: zodResolver(dynamicSchema),
    defaultValues,
    mode: "onSubmit",
  })

  //console.log("Form errors:", form.formState.errors)

  const id = values?.id ?? (values as any)?.id

  async function onSubmit(values: Record<string, any>) {
    let res: any

    if (values.main_image instanceof File) {
      const formData = new FormData()

      formData.append("file", values.main_image)

      const uploadRes = await fetch("/api/upload/create", {
        method: "POST",
        body: formData,
      })

      const uploadData = await uploadRes.json()

      values.main_image = {
        path: uploadData.path,
        size: values.main_image.size,
        name: values.main_image.name,
      }
    } else if (values.main_image?.preview) {
      // existing DB image
      values.main_image = {
        path: values.main_image.preview,
        size: values.main_image.size || 0,
        name: values.main_image.name || "Main Image",
      }
    }

    const galleryFiles = Array.isArray(values.gallery) ? values.gallery : []

    const galleryPaths = []

    for (const file of galleryFiles) {
      // skip existing DB images
      if (file.preview && !file.path) {
        galleryPaths.push({
          path: file.preview,
          size: file.size || 0,
          name: file.name,
        })

        continue
      }

      // upload new files only
      if (file instanceof File) {
        const fd = new FormData()

        fd.append("file", file)

        const res = await fetch("/api/upload/create", {
          method: "POST",
          body: fd,
        })

        const data = await res.json()

        galleryPaths.push({
          path: data.path,
          size: file.size,
          name: file.name,
        })
      }
    }

    values.gallery = galleryPaths

    if (id) {
      res = await updateHotel(id, values)
    } else {
      res = await createHotel(values)
    }

    if (res.success) {
      // delete removed gallery files
      for (const file of deletedGallery) {
        await fetch("/api/upload/delete", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            path: file.preview || file.path,
          }),
        })
      }

      // delete removed main image
      for (const file of deletedMainImage) {
        await fetch("/api/upload/delete", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            path: file.preview || file.path,
          }),
        })
      }

      toast.success(
        `${entity.charAt(0).toUpperCase() + entity.slice(1)} updated successfully!`
      )
      router.refresh()
    } else {
      toast.error(res.error)
    }
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit, onError)}>
        <Card>
          <CardContent className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
            {fields
              .sort(
                (a, b) =>
                  (a.sort_order ?? Infinity) - (b.sort_order ?? Infinity)
              )
              .map((field, index) => {
                switch (field.type) {
                  case "text":
                  case "number":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={field.name}
                        render={({ field: formField }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>
                            <FormControl>
                              <Input
                                type={field.type}
                                placeholder={field.label}
                                className={
                                  form.formState.errors[field.name]
                                    ? "border-red-500 focus-visible:ring-red-500"
                                    : ""
                                }
                                {...formField}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  case "textarea":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={field.name}
                        render={({ field: formField }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>
                            <FormControl>
                              <Textarea
                                placeholder={field.label}
                                className={
                                  form.formState.errors[field.name]
                                    ? "border-red-500 focus-visible:ring-red-500"
                                    : ""
                                }
                                {...formField}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  case "multiselect":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={field.name}
                        render={({ field: formField, fieldState }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>
                            <FormControl>
                              <MultiSelect
                                options={field.options || []}
                                selected={
                                  Array.isArray(formField.value)
                                    ? formField.value.map((item: any) =>
                                        String(item)
                                      )
                                    : formField.value
                                      ? [String(formField.value)]
                                      : []
                                }
                                onChange={formField.onChange}
                                placeholder={`Select ${field.label}`}
                                className={
                                  form.formState.errors[field.name]
                                    ? "border-red-500 focus-visible:ring-red-500"
                                    : ""
                                }
                                invalid={!!fieldState.error}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  case "select":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={`${field.name}-${index}`}
                        render={({ field: formField, fieldState }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>

                            <Select
                              value={formField.value || ""}
                              onValueChange={formField.onChange}
                            >
                              <FormControl>
                                <SelectTrigger
                                  className={
                                    form.formState.errors[field.name]
                                      ? "border-red-500 focus-visible:ring-red-500"
                                      : ""
                                  }
                                >
                                  <SelectValue
                                    placeholder={`Select ${field.label}`}
                                  />
                                </SelectTrigger>
                              </FormControl>

                              <SelectContent>
                                {field.options?.map(
                                  (option: any, index: number) => (
                                    <SelectItem
                                      key={`${option.value ?? option}-${index}`}
                                      value={String(option.value ?? option)}
                                    >
                                      {option.label ?? option}
                                    </SelectItem>
                                  )
                                )}
                              </SelectContent>
                            </Select>

                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  case "file":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={`${field.name}-${index}`}
                        render={({ field: formField }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>

                            <FileUpload
                              value={mainImage}
                              onValueChange={(files) => {
                                const updated = files.slice(0, 1)
                                setMainImage(updated)
                                formField.onChange(updated[0] || null)
                              }}
                              maxFiles={1}
                            >
                              <FileUploadDropzone />

                              <FileUploadList>
                                {mainImage.map((file, index) => (
                                  <FileUploadItem key={index} value={file}>
                                    <FileUploadItemPreview file={file} />

                                    <FileUploadItemMetadata file={file} />

                                    <button
                                      type="button"
                                      onClick={() => {
                                        const updated = mainImage.filter(
                                          (_, i) => i !== index
                                        )

                                        setMainImage(updated)

                                        formField.onChange(updated)

                                        const removedFile = mainImage[index]

                                        if (
                                          removedFile?.preview ||
                                          removedFile?.path
                                        ) {
                                          setDeletedMainImage((prev) => [
                                            ...prev,
                                            removedFile,
                                          ])
                                        }
                                      }}
                                    >
                                      <X className="h-4 w-4" />
                                    </button>
                                  </FileUploadItem>
                                ))}
                              </FileUploadList>
                            </FileUpload>

                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )

                  case "gallery":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={`${field.name}-${index}`}
                        render={({ field: formField }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="flex flex-col gap-2"
                          >
                            <FormLabel>{field.label}</FormLabel>

                            <FileUpload
                              value={gallery}
                              onValueChange={(files) => {
                                setGallery(files)
                                formField.onChange(files)
                              }}
                              multiple
                              maxFiles={10}
                            >
                              <FileUploadDropzone />

                              <FileUploadList>
                                {gallery.map((file, index) => (
                                  <FileUploadItem key={index} value={file}>
                                    <FileUploadItemPreview file={file} />

                                    <FileUploadItemMetadata file={file} />

                                    <button
                                      type="button"
                                      onClick={() => {
                                        const removedFile = gallery[index]

                                        // only track uploaded files
                                        if (
                                          removedFile?.preview ||
                                          removedFile?.path
                                        ) {
                                          setDeletedGallery((prev) => [
                                            ...prev,
                                            removedFile,
                                          ])
                                        }

                                        const updated = gallery.filter(
                                          (_, i) => i !== index
                                        )

                                        setGallery(updated)

                                        formField.onChange(updated)
                                      }}
                                    >
                                      <X className="h-4 w-4" />
                                    </button>
                                  </FileUploadItem>
                                ))}
                              </FileUploadList>
                            </FileUpload>

                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  case "room_pricing":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={field.name}
                        render={({ field: formField }) => (
                          <FormItem
                            ref={(el) => {
                              fieldRefs.current[field.name] = el
                            }}
                            className="md:col-span-2"
                          >
                            <FormLabel>{field.label}</FormLabel>

                            <div className="space-y-4">
                              {/* Heading */}
                              <div className="grid grid-cols-4 gap-2 px-1">
                                <div className="text-sm font-medium text-muted-foreground">
                                  Rooms
                                </div>

                                <div className="text-sm font-medium text-muted-foreground">
                                  Days
                                </div>

                                <div className="text-sm font-medium text-muted-foreground">
                                  Price
                                </div>

                                <div className="text-sm font-medium text-muted-foreground">
                                  Action
                                </div>
                              </div>
                              {roomPricing.map((item, idx) => (
                                <div
                                  key={idx}
                                  className="grid grid-cols-4 gap-2 rounded-lg border p-4"
                                >
                                  <Input
                                    type="number"
                                    placeholder="Rooms"
                                    value={item.room_count}
                                    onChange={(e) => {
                                      const updated = [...roomPricing]

                                      updated[idx].room_count = Number(
                                        e.target.value
                                      )

                                      setRoomPricing(updated)

                                      formField.onChange(updated)
                                    }}
                                  />

                                  <Input
                                    type="number"
                                    placeholder="Days"
                                    value={item.days_count}
                                    onChange={(e) => {
                                      const updated = [...roomPricing]

                                      updated[idx].days_count = Number(
                                        e.target.value
                                      )

                                      setRoomPricing(updated)

                                      formField.onChange(updated)
                                    }}
                                  />

                                  <Input
                                    type="number"
                                    placeholder="Price"
                                    value={item.price}
                                    onChange={(e) => {
                                      const updated = [...roomPricing]

                                      updated[idx].price = Number(
                                        e.target.value
                                      )

                                      setRoomPricing(updated)

                                      formField.onChange(updated)
                                    }}
                                  />

                                  <Button
                                    type="button"
                                    title="Remove row"
                                    variant="destructive"
                                    size="icon"
                                    onClick={() => {
                                      const updated = roomPricing.filter(
                                        (_, i) => i !== idx
                                      )

                                      setRoomPricing(updated)

                                      formField.onChange(updated)
                                    }}
                                  >
                                    <TrashIcon className="h-4 w-4" />
                                  </Button>
                                </div>
                              ))}

                              <Button
                                type="button"
                                className="rounded-lg bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700 focus:ring-4 focus:ring-blue-300"
                                title="Add Row"
                                onClick={() => {
                                  const updated = [
                                    ...roomPricing,
                                    {
                                      room_count: 1,
                                      days_count: 1,
                                      price: 0,
                                    },
                                  ]

                                  setRoomPricing(updated)

                                  formField.onChange(updated)
                                }}
                              >
                                <PlusIcon className="h-4 w-4" />
                              </Button>
                            </div>

                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )

                  case "richtext":
                    return (
                      <FormField
                        control={form.control}
                        name={field.name}
                        key={field.name}
                        render={({ field: formField }) => (
                          <FormItem className="col-span-2 flex flex-col gap-2">
                            <FormLabel>{field.label}</FormLabel>

                            <FormControl>
                              <RichTextEditor
                                value={formField.value || ""}
                                onChange={formField.onChange}
                                maxLength={field.max_length}
                              />
                            </FormControl>

                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    )
                  default:
                    return null
                }
              })}
          </CardContent>
          <CardFooter>
            <Button type="submit" disabled={form.formState.isSubmitting}>
              {form.formState.isSubmitting
                ? id
                  ? "Updating..."
                  : "Creating..."
                : id
                  ? "Update"
                  : "Create"}
            </Button>
          </CardFooter>
        </Card>
      </form>
    </Form>
  )
}
