"use client"

import * as React from "react"
import { useForm, Controller } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"
import {
  Dialog,
  DialogContent,
  DialogTitle,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { ReactSelect } from "@/components/ui/react-select"
import {
  Combobox,
  ComboboxContent,
  ComboboxEmpty,
  ComboboxInput,
  ComboboxItem,
  ComboboxList,
} from "@/components/ui/combobox"
import { DatePicker } from "@/components/ui/date-picker"
import { DateTimePicker } from "@/components/ui/date-time-picker"
import { toast } from "sonner"
import {
  useGetAllUsersQuery,
  useGetProfileQuery,
  useGetTaskStatusesQuery,
} from "@/api/rtk"
import { triggerTaskHandedToAE } from "@/store/slices/automation-slice"
import { useAppDispatch } from "@/store/hooks"
import {
  TASK_MODULE_TYPE_LABELS,
  TASK_MODULE_TYPES,
  KNOWN_TASK_STATUS_CODES,
  TASK_STATUS_FALLBACK_LABELS,
  type Task,
  type TaskModuleType,
  type TaskStatus,
  type TaskPriority,
  useCreateTaskMutation,
  useUpdateTaskMutation,
} from "@/api/rtk/tasks-api"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Info } from "lucide-react"

const buildSchema = (allowedStatusCodes: string[]) =>
  yup.object({
    title: yup.string().min(1, "Title is required").required("Title is required"),
    description: yup.string().optional(),
    status: yup
      .string()
      .required()
      .oneOf(allowedStatusCodes, "Invalid task status"),
    priority: yup.string().oneOf(["LOW", "MEDIUM", "HIGH", "URGENT"]).required(),
    moduleType: yup.string().oneOf(["LEAD", "DEAL", "CUSTOMER", "PROJECTS"]).required(),
    dueDate: yup.date().optional().nullable(),
    reminderAt: yup.date().optional().nullable(),
    dealId: yup.string().optional(),
    assignedToId: yup.string().min(1, "Assignee is required").required("Assignee is required"),
  })

type FormValues = yup.InferType<ReturnType<typeof buildSchema>>

type PickerUser = { id: string; name: string }

interface Props {
  open: boolean
  onClose: () => void
  task?: Task | null
  dealId?: string
  /** When set, only these user IDs appear in "Assigned To" (e.g. deal team members in Scoping). */
  assignableUserIds?: string[] | null
  /** Dialog title override (e.g. "Assign task"). */
  title?: string
  /** Default CRM module for new tasks (edit mode uses the task’s saved value). */
  defaultModuleType?: TaskModuleType
}

const PRIORITY_LABELS: Record<string, string> = {
  LOW: "Low",
  MEDIUM: "Medium",
  HIGH: "High",
  URGENT: "Urgent",
}

/** Base UI Combobox portals to body; modal Dialog uses disableOutsidePointerEvents and blocks those clicks. */
function isInsideComboboxLayer(node: EventTarget | null): boolean {
  return (
    node instanceof Element &&
    Boolean(
      node.closest('[data-slot="combobox-content"]') ||
      node.closest('[data-slot="combobox-item"]') ||
      node.closest('[data-slot="combobox-list"]'),
    )
  )
}

export function TaskFormModal({
  open,
  onClose,
  task,
  dealId,
  assignableUserIds,
  title,
  defaultModuleType = "DEAL",
}: Props) {
  const dispatch = useAppDispatch()
  const isEdit = !!task
  const [createTask, { isLoading: creating }] = useCreateTaskMutation()
  const [updateTask, { isLoading: updating }] = useUpdateTaskMutation()
  const { data: users = [] } = useGetAllUsersQuery(undefined)
  const { data: profile } = useGetProfileQuery()
  const { data: taskStatuses = [], isLoading: taskStatusesLoading } =
    useGetTaskStatusesQuery()
  const currentUserId = profile?.id ?? profile?._id ?? ""

  const allowedStatusCodes = React.useMemo(() => {
    if (taskStatusesLoading) return [...KNOWN_TASK_STATUS_CODES]
    return taskStatuses.length > 0
      ? taskStatuses.map((s) => s.code)
      : [...KNOWN_TASK_STATUS_CODES]
  }, [taskStatuses, taskStatusesLoading])

  const statusSelectRows = React.useMemo(() => {
    if (taskStatuses.length > 0) return taskStatuses
    return KNOWN_TASK_STATUS_CODES.map((code) => ({
      code,
      name: TASK_STATUS_FALLBACK_LABELS[code],
      sortOrder: 0,
    }))
  }, [taskStatuses])

  const schema = React.useMemo(
    () => buildSchema(allowedStatusCodes),
    [allowedStatusCodes],
  )
  const resolver = React.useMemo(() => yupResolver(schema), [schema])

  /** Assignee editing their own task: cannot change who the task is assigned to. */
  const hideAssigneePicker =
    isEdit && !!task?.assignedToId && currentUserId !== "" && task.assignedToId === currentUserId

  const assignableIdSet = React.useMemo(() => {
    if (assignableUserIds === undefined || assignableUserIds === null) return null
    return new Set(assignableUserIds)
  }, [assignableUserIds])

  const pickerUsers = React.useMemo((): PickerUser[] => {
    if (!assignableIdSet) return users as PickerUser[]
    const filtered = (users as PickerUser[]).filter((u) => assignableIdSet.has(u.id))
    if (isEdit && task?.assignedToId && !assignableIdSet.has(task.assignedToId)) {
      const current = (users as PickerUser[]).find((u) => u.id === task.assignedToId)
      return current ? [...filtered, current] : filtered
    }
    return filtered
  }, [users, assignableIdSet, isEdit, task?.assignedToId])

  const pickerUserIds = React.useMemo(() => pickerUsers.map((u) => u.id), [pickerUsers])

  const userNameById = React.useMemo(() => {
    const m = new Map<string, string>()
    for (const u of pickerUsers) {
      m.set(u.id, u.name)
    }
    return m
  }, [pickerUsers])

  const {
    register,
    handleSubmit,
    control,
    reset,
    formState: { errors },
  } = useForm<any>({
    resolver,
    defaultValues: {
      title: task?.title ?? "",
      description: task?.description ?? "",
      status: (task?.status as any) ?? "TODO",
      priority: (task?.priority as any) ?? "MEDIUM",
      moduleType: task?.moduleType ?? defaultModuleType ?? "DEAL",
      dueDate: task?.dueDate ? new Date(task.dueDate) : null,
      reminderAt: task?.reminderAt ? new Date(task.reminderAt) : null,
      dealId: task?.dealId ?? dealId ?? "",
      assignedToId: task?.assignedToId ?? "",
    },
  })

  React.useEffect(() => {
    if (open) {
      reset({
        title: task?.title ?? "",
        description: task?.description ?? "",
        status: (task?.status as any) ?? "TODO",
        priority: (task?.priority as any) ?? "MEDIUM",
        moduleType: task?.moduleType ?? defaultModuleType ?? "DEAL",
        dueDate: task?.dueDate ? new Date(task.dueDate) : null,
        reminderAt: task?.reminderAt ? new Date(task.reminderAt) : null,
        dealId: task?.dealId ?? dealId ?? "",
        assignedToId: task?.assignedToId ?? "",
      })
    }
  }, [open, task, dealId, defaultModuleType, reset])

  const onSubmit = async (values: FormValues) => {
    if (
      !hideAssigneePicker &&
      assignableIdSet &&
      assignableIdSet.size > 0 &&
      !assignableIdSet.has(values.assignedToId)
    ) {
      toast.error("Choose someone on this deal’s team")
      return
    }
    try {
      const dealIdTrim = values.dealId?.trim()
      const payload = {
        title: values.title.trim(),
        description: values.description?.trim() || undefined,
        status: values.status as TaskStatus,
        priority: values.priority as TaskPriority,
        moduleType: values.moduleType as TaskModuleType,
        dueDate: values.dueDate ? values.dueDate.toISOString() : undefined,
        reminderAt: values.reminderAt ? values.reminderAt.toISOString() : undefined,
        dealId: dealIdTrim || undefined,
        assignedToId: values.assignedToId,
      }

      if (isEdit && task) {
        await updateTask({ id: task.id, body: payload }).unwrap()
        toast.success("Task updated")
      } else {
        await createTask(payload).unwrap()
        toast.success("Task created")
      }

      if (payload.status === "HANDED_TO_AE" && payload.dealId) {
        console.log("[Modal] Status is HANDED_TO_AE. Dispatching Redux action...");
        dispatch(triggerTaskHandedToAE(payload.dealId))
      }

      onClose()
    } catch (e: unknown) {
      const data = e && typeof e === "object" && "data" in e ? (e as { data?: unknown }).data : undefined
      let msg: string | undefined
      if (data && typeof data === "object" && data !== null) {
        const o = data as { message?: string | string[] }
        if (Array.isArray(o.message)) msg = o.message.join(", ")
        else if (typeof o.message === "string") msg = o.message
      }
      toast.error(msg || "Something went wrong")
    }
  }



  return (
    <Dialog modal={false} open={open} onOpenChange={(v) => !v && onClose()}>
      <DialogContent
        className="max-w-lg max-h-[90vh] flex flex-col"
        onPointerDownOutside={(e) => {
          const target = e.detail.originalEvent.target
          if (isInsideComboboxLayer(target)) {
            e.preventDefault()
          }
        }}
        onFocusOutside={(e) => {
          const related = e.detail.originalEvent.relatedTarget
          if (isInsideComboboxLayer(related)) {
            e.preventDefault()
          }
        }}
        onInteractOutside={(e) => {
          const oe = e.detail.originalEvent
          if (oe instanceof PointerEvent && isInsideComboboxLayer(oe.target)) {
            e.preventDefault()
            return
          }
          if (oe instanceof FocusEvent && isInsideComboboxLayer(oe.relatedTarget)) {
            e.preventDefault()
          }
        }}
      >
        <DialogTitle className="shrink-0">{title ?? (isEdit ? "Edit Task" : "New Task")}</DialogTitle>
        <form
          onSubmit={handleSubmit(onSubmit, (err) => {
            console.error("Validation errors:", err)
            const firstError = Object.values(err)[0]
            if (firstError?.message) toast.error(String(firstError.message))
          })}
          className="flex flex-col flex-1 overflow-hidden mt-2"
        >
          <div className="flex flex-col gap-4 overflow-y-auto overflow-x-hidden px-1 pb-2 flex-1 scrollbar-themed">
            {/* Title */}
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium">Title *</label>
            <Input {...register("title")} placeholder="Task title" />
            {errors.title?.message && (
              <p className="text-xs text-red-500">{String(errors.title.message)}</p>
            )}
          </div>

          {/* Description */}
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium">Description</label>
            <Textarea
              {...register("description")}
              placeholder="Optional description"
              rows={3}
            />
          </div>

          {/* Status & Priority */}
          <div className="grid grid-cols-2 gap-3">
            <div className="flex flex-col gap-1">
              <label className="text-sm font-medium">Status</label>
              <Controller
                name="status"
                control={control}
                render={({ field }) => (
                  <ReactSelect
                    value={field.value}
                    onValueChange={field.onChange}
                    options={statusSelectRows.map((row) => ({
                      value: row.code,
                      label: row.name,
                    }))}
                    aria-label="Status"
                  />
                )}
              />
            </div>
            <div className="flex flex-col gap-1">
              <label className="text-sm font-medium">Priority</label>
              <Controller
                name="priority"
                control={control}
                render={({ field }) => (
                  <ReactSelect
                    value={field.value}
                    onValueChange={field.onChange}
                    options={Object.entries(PRIORITY_LABELS).map(([v, l]) => ({
                      value: v,
                      label: l,
                    }))}
                    aria-label="Priority"
                  />
                )}
              />
            </div>
          </div>


          {/* Due Date */}
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium">Due Date</label>
            <Controller
              name="dueDate"
              control={control}
              render={({ field }) => (
                <DatePicker
                  value={field.value ?? undefined}
                  onChange={(d) => {
                    if (!d) field.onChange(null)
                    else {
                      // DatePicker returns "yyyy-MM-dd", parse it properly
                      const parsed = new Date(d)
                      field.onChange(isNaN(parsed.getTime()) ? null : parsed)
                    }
                  }}
                  placeholder="Pick a due date"
                  calendarProps={{
                    disabled: { before: new Date() }
                  }}
                />
              )}
            />
            {errors.dueDate?.message && (
              <p className="text-xs text-red-500">{String(errors.dueDate.message)}</p>
            )}
          </div>

          {/* Reminder Date */}
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium">Reminder Date & Time</label>
            <Controller
              name="reminderAt"
              control={control}
              render={({ field }) => (
                <DateTimePicker
                  value={field.value ? field.value.toISOString() : undefined}
                  onChange={(d) => {
                    if (!d) field.onChange(null)
                    else {
                      const parsed = new Date(d)
                      field.onChange(isNaN(parsed.getTime()) ? null : parsed)
                    }
                  }}
                  placeholder="Set a reminder"
                  min={new Date().toISOString()}
                />
              )}
            />
            {errors.reminderAt?.message && (
              <p className="text-xs text-red-500">{String(errors.reminderAt.message)}</p>
            )}
          </div>

          {/* Assigned To — hidden when you are the assignee (you can’t reassign yourself here) */}
          {hideAssigneePicker ? (
            <Alert className="w-full">
              <Info className="size-4" aria-hidden />
              <AlertTitle>Assigned to you</AlertTitle>
              <AlertDescription>
                Only a teammate or admin can change who this task is assigned to.
              </AlertDescription>
            </Alert>
          ) : (
            <div className="flex flex-col gap-1">
              <label className="text-sm font-medium">Assigned To *</label>
              {assignableIdSet && pickerUsers.length === 0 ? (
                <p className="text-xs text-amber-700 rounded-md border border-amber-200 bg-amber-50 px-3 py-2">
                  No users match this deal’s team in the directory. Check Team membership in Settings.
                </p>
              ) : (
                <Controller
                  name="assignedToId"
                  control={control}
                  render={({ field }) => (
                    <Combobox
                      items={pickerUserIds}
                      value={field.value ?? ""}
                      onValueChange={(v) => field.onChange(v ?? "")}
                      itemToStringLabel={(id) =>
                        userNameById.get(id) ?? (id ? "User" : "")
                      }
                    >
                      <ComboboxInput
                        placeholder="Search users…"
                        className="h-10 w-full rounded-md border border-input bg-background text-sm shadow-xs"
                        aria-label="Assign to user"
                        aria-invalid={!!errors.assignedToId}
                      />
                      <ComboboxContent
                        className="z-[200] w-[var(--anchor-width)] min-w-[min(100vw-2rem,24rem)] rounded-md border bg-popover shadow-lg"
                        align="start"
                        sideOffset={4}
                      >
                        <ComboboxEmpty>No users match your search.</ComboboxEmpty>
                        <ComboboxList>
                          {(userId) => {
                            const u = pickerUsers.find((x) => x.id === userId)
                            if (!u) return null
                            return (
                              <ComboboxItem key={userId} value={userId}>
                                {u.name}
                              </ComboboxItem>
                            )
                          }}
                        </ComboboxList>
                      </ComboboxContent>
                    </Combobox>
                  )}
                />
              )}
              {assignableIdSet && pickerUsers.length > 0 && (
                <p className="text-xs text-muted-foreground">Only members assigned to this deal’s team are listed.</p>
              )}
              {errors.assignedToId?.message && (
                <p className="text-xs text-red-500">{String(errors.assignedToId.message)}</p>
              )}
            </div>
          )}

          </div>

          <div className="flex justify-end gap-2 pt-4 mt-2 border-t border-border/40 shrink-0">
            <Button type="button" variant="outline" onClick={onClose}>
              Cancel
            </Button>
            <Button
              type="submit"
              disabled={creating || updating}
            >
              {creating || updating ? "Saving..." : isEdit ? "Save Changes" : "Create Task"}
            </Button>
          </div>
        </form>
      </DialogContent>
    </Dialog>
  )
}
