import React, { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import {
  Table,
  Button,
  Form,
  Input,
  Select,
  Popconfirm,
  Col,
  Row,
  Tag,
  Card,
  Pagination,
  Typography,
} from "antd";
import {
  Plus,
  Edit,
  Trash2,
  Search,
  UserCog,
  Mail,
  Phone,
  CheckCircle,
  XCircle,
} from "lucide-react";
import {
  useForm,
  Controller,
  type SubmitHandler,
  Resolver,
} from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import type { ColumnsType } from "antd/es/table";
import { API_Instance } from "../../api/axios.instance";
import API_Constants from "../../constants/api.constants";
import { IOptionsList, IStaffMember, ISubjectTopics } from "@/types";
import toast from "react-hot-toast";
import { getAxiosErrorMessage, getOptionLabel } from "@/utils/index.utils";
import Modal from "@/components/shared/Modal";
import { useDebounce } from "@/hooks/useDebounce";
const { Text } = Typography;

type StaffFormValues = Omit<IStaffMember, "id"> & { password?: string };

const schema = yup.object({
  firstName: yup.string().required("First Name is required"),
  lastName: yup.string().required("Last Name is required"),
  email: yup.string().email("Invalid email").required("Email is required"),
  phone: yup.string().required("Phone is required"),
  // designation: yup.string().required("Designation is required"),
  password: yup.string().when("$isEdit", {
    is: true,
    then: (schema) => schema.notRequired(),
    otherwise: (schema) => schema.required("Password is required"),
  }),
  role: yup.mixed<"Staff">().oneOf(["Staff"]).required("Role is required"),
  roleId: yup.string().required("Role is required"),
  subjects: yup
    .array()
    .of(yup.string())
    .min(1, "At least one subject is required"),
});

const filterInitial = {
  search: "",
  isVerified: undefined,
  roleId: undefined,
  subjectId: undefined,
};

const initialFormValues: StaffFormValues = {
  firstName: "",
  lastName: "",
  email: "",
  phone: "",
  // designation: "",
  password: "",
  role: "Staff",
  roleId: undefined,
  subjects: [],
};

const StaffManagement: React.FC = () => {
  const [staff, setStaff] = useState<IStaffMember[]>([]);
  const [loading, setLoading] = useState(false);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [editingStaff, setEditingStaff] = useState<IStaffMember | null>(null);
  const [options, setOptions] = useState<IOptionsList>({
    subjects: [],
    roles: [],
  });

  const { state } = useLocation();
  const [filterValues, setFilterValues] = useState(() => {
    if (state?.isVerified !== undefined) {
      return {
        ...filterInitial,
        isVerified: state.isVerified,
      };
    }
    return filterInitial;
  });
  const [page, setPage] = useState(1);
  const [limit, setLimit] = useState(10);
  const [total, setTotal] = useState(0);
  const debouncedSearch = useDebounce(filterValues.search, 600);
  const [roleSearch, setRoleSearch] = useState("");
  const [subjectSearch, setSubjectSearch] = useState("");
  const debouncedRoleSearch = useDebounce(roleSearch, 500);
  const debouncedSubjectSearch = useDebounce(subjectSearch, 500);
  const [subjectPage, setSubjectPage] = useState(1);
  const [hasMoreSubjects, setHasMoreSubjects] = useState(true);
  const [loadingSubjects, setLoadingSubjects] = useState(false);

  const resolver = yupResolver(schema) as unknown as Resolver<StaffFormValues>;

  const {
    control,
    handleSubmit,
    reset,
    watch,
    setError,
    clearErrors,
    setValue,
    getValues,
    formState: { errors, isSubmitting },
  } = useForm<StaffFormValues>({
    resolver,
    context: { isEdit: !!editingStaff },
    defaultValues: initialFormValues,
  });

  const debouncedEmail = useDebounce(watch("email"), 600);

  const buildQuery = (filters: any, page: number, limit: number) => {
    const params = new URLSearchParams();

    params.append("page", page.toString());
    params.append("limit", limit.toString());

    Object.entries(filters).forEach(([key, val]) => {
      if (val !== "" && val !== undefined && val !== null) {
        params.append(key, val.toString());
      }
    });

    return params.toString();
  };

  // --- Fetch Staff ---
  const fetchStaff = async (page = 1, limit = 10, filter = filterValues) => {
    setLoading(true);
    try {
      const res = await API_Instance.get(
        `${API_Constants.staff}?${buildQuery(filter, page, limit)}`,
      );
      setStaff(res.data.data);
      setTotal(res.data.meta.total);
      setPage(res.data.meta.page);
      setLimit(res.data.meta.limit);
    } catch (error) {
      toast.error(getAxiosErrorMessage(error));
    } finally {
      setLoading(false);
    }
  };

  const fetchSubjects = async (search = "", page = 1) => {
    setLoadingSubjects(true);
    try {
      const subjectRes = await API_Instance.get(API_Constants.subjects, {
        params: {
          search,
          page,
          limit: 10,
        },
      });

      const newSubjects = subjectRes?.data?.data
        .map((opt: any) => ({
          label: opt.subjectName,
          value: opt.id,
        }))
        .sort((a: any, b: any) => a.label.localeCompare(b.label));

      setOptions((prev) => {
        let updatedSubjects = page === 1 ? newSubjects : [...prev.subjects, ...newSubjects];
        
        const selectedValues: any[] = getValues("subjects") || [];
        const existingSelected = prev.subjects.filter(s => selectedValues.includes(s.value));
        const updatedIds = new Set(updatedSubjects.map((s: any) => s.value));
        
        const missingSelected = existingSelected.filter(s => !updatedIds.has(s.value));
        
        if (missingSelected.length > 0) {
          updatedSubjects = [...updatedSubjects, ...missingSelected].sort((a: any, b: any) => a.label.localeCompare(b.label));
        }

        return {
          ...prev,
          subjects: updatedSubjects,
        };
      });
      setHasMoreSubjects(newSubjects?.length === 10);
    } catch (error) {
      toast.error(getAxiosErrorMessage(error));
    } finally {
      setLoadingSubjects(false);
    }
  };
  const fetchRoles = async (search = "") => {
    setLoading(true);
    try {
      const rolesRes = await API_Instance.get(API_Constants.roles, {
        params: {
          search,
        },
      });

      setOptions((prev) => ({
        ...prev,
        roles: rolesRes?.data?.data
          .map((opt: any) => ({
            label: opt.roleName,
            value: opt.id,
          }))
          .sort((a: any, b: any) => a.label.localeCompare(b.label)),
      }));
    } catch (error) {
      toast.error(getAxiosErrorMessage(error));
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchStaff(page, limit, filterValues);
    fetchRoles();
  }, []);

  // Modal handlers
  const openModal = (staffMember: IStaffMember | null = null) => {
    setEditingStaff(staffMember);
    
    if (staffMember && staffMember.subjects) {
      setOptions(prev => {
        const existingSubjectIds = new Set(prev.subjects.map(s => s.value));
        const missingSubjects = staffMember.subjects
          .filter((sub: any) => typeof sub !== 'string' && !existingSubjectIds.has(sub.id))
          .map((sub: any) => ({
            label: sub.subjectName,
            value: sub.id
          }));
        
        if (missingSubjects.length > 0) {
          return {
            ...prev,
            subjects: [...prev.subjects, ...missingSubjects].sort((a, b) => a.label.localeCompare(b.label))
          };
        }
        return prev;
      });
    }

    reset({
      firstName: staffMember?.firstName || "",
      lastName: staffMember?.lastName || "",
      email: staffMember?.email || "",
      phone: staffMember?.phone || "",
      // designation: staffMember?.designation || "",
      password: "",
      role: staffMember?.role || "Staff",
      roleId: staffMember?.roleId || "",
      subjects: staffMember?.subjects.map((item: any) => typeof item === 'string' ? item : item.id) || [],
    });
    setIsModalOpen(true);
  };

  const closeModal = () => {
    setEditingStaff(null);
    setIsModalOpen(false);
    reset(initialFormValues);
  };

  // Form submit
  const onFormSubmit: SubmitHandler<StaffFormValues> = async (data) => {
    try {
      if (editingStaff) {
        const { password, ...restData } = data;
        const res = await API_Instance.put(
          `${API_Constants.staff}/${editingStaff.id}`,
          restData,
        );
        toast.success(res.data.message);
      } else {
        const res = await API_Instance.post(API_Constants.staff, data);
        toast.success(res.data.message);
      }
      fetchStaff(page, limit, filterValues);
    } catch (err) {
      toast.error(getAxiosErrorMessage(err));
    } finally {
      closeModal();
    }
  };

  // --- Delete ---
  const handleDelete = async (id: string) => {
    try {
      const res = await API_Instance.delete(`${API_Constants.staff}/${id}`);
      toast.success(res.data.message);
      fetchStaff(page, limit, filterValues);
    } catch (err) {
      toast.error(getAxiosErrorMessage(err));
    }
  };

  // Table columns
  const columns: ColumnsType<IStaffMember> = [
    {
      title: "Name",
      key: "name",
      render: (_, record) => `${record.firstName} ${record.lastName}`,
    },
    {
      title: "Email & Phone",
      key: "emailPhone",
      render: (_, record) => (
        <div className="flex flex-col gap-1 text-sm text-slate-600">
          <div className="flex items-center gap-1">
            <Mail size={14} className="text-slate-400" />
            <span className="text-md">{record.email}</span>
          </div>
          {record.phone && (
            <div className="flex items-center gap-1">
              <Phone size={14} className="text-slate-400" />
              <span className="text-sm">{record.phone}</span>
            </div>
          )}
        </div>
      ),
    },
    {
      title: "Verified",
      key: "verified",
      render: (_, record) => (
        <Tag
          color={record.isVerified ? "success" : "warning"}
          className="flex w-fit items-center gap-1"
        >
          {record.isVerified ? (
            <CheckCircle size={12} />
          ) : (
            <XCircle size={12} />
          )}
          {record.isVerified ? "Verified" : "Pending"}
        </Tag>
      ),
    },
    {
      title: "Role",
      dataIndex: "roleId",
      key: "role",
      render: (roleId: string) => (
        <Tag color="blue" className="rounded-full border-none">
          {getOptionLabel(options.roles, roleId)}
        </Tag>
      ),
    },
    {
      title: "Subjects",
      key: "subjects",
      dataIndex: "subjects",
      render: (subjects: ISubjectTopics[] = []) => (
        <div className="flex flex-wrap gap-1">
          {subjects.length > 0 ? (
            subjects.map((sub) => (
              <Tag
                key={sub.id}
                color="success"
                className="rounded-full border-none"
              >
                {sub.subjectName}
              </Tag>
            ))
          ) : (
            <span style={{ color: "#999" }}>No subjects</span>
          )}
        </div>
      ),
    },
    // {
    //   title: "Exams",
    //   key: "exams",
    //   dataIndex: "exams",
    //   render: (exams: string[] = []) => (
    //     <div className="flex flex-wrap gap-1">
    //       {exams.length > 0 ? (
    //         exams.map((exam) => (
    //           <Tag
    //             key={exam}
    //             color="processing"
    //             className="rounded-full border-none"
    //           >
    //             {getOptionLabel(options.exams, exam)}
    //           </Tag>
    //         ))
    //       ) : (
    //         <span style={{ color: "#999" }}>No exams</span>
    //       )}
    //     </div>
    //   ),
    // },
    {
      title: "Referral Code",
      key: "Referral Code",
      render: (_, record) => (
        record.referralCode
      ),
      width: 150,
    },
    {
      title: "Actions",
      key: "actions",
      render: (_, record) => (
        <div className="flex space-x-2">
          <button
            onClick={() => openModal(record)}
            className="text-[#1677ff] hover:text-[#579af8]"
          >
            <Edit className="h-5 w-5" />
          </button>
          <Popconfirm
            title="Delete staff?"
            onConfirm={() => handleDelete(record.id)}
            okText="Yes"
            cancelText="No"
          >
            <button className="text-red-600 hover:text-red-800">
              <Trash2 className="h-5 w-5" />
            </button>
          </Popconfirm>
        </div>
      ),
    },
  ];

  const handleSelectAll = (
    value: string[],
    onChange: any,
    allOptions: any[],
  ) => {
    if (value.includes("all")) {
      const alreadyAllSelected = value.length > allOptions.length;

      if (alreadyAllSelected) {
        onChange([]);
        return;
      }
      const allIds = allOptions.map((opt) => opt.value);
      onChange(allIds);
    } else {
      onChange(value);
    }
  };

  useEffect(() => {
    fetchStaff(page, limit, { ...filterValues, search: debouncedSearch });
  }, [
    page,
    limit,
    debouncedSearch,
    filterValues.isVerified,
    filterValues.roleId,
    filterValues.subjectId,
  ]);

  useEffect(() => {
    if (editingStaff) return;
    if (!debouncedEmail) {
      clearErrors("email");
      return;
    }

    // basic email regex guard
    // const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    // if (!emailRegex.test(debouncedEmail)) return;

    const controller = new AbortController();

    API_Instance.get(`${API_Constants.users}/check-email`, {
      params: { email: debouncedEmail },
      signal: controller.signal,
    })
      .then((res) => {
        if (res.data.exists) {
          setError("email", {
            type: "manual",
            message: "Email already in use",
          });
        } else {
          clearErrors("email");
        }
      })
      .catch(() => { });

    return () => controller.abort();
  }, [debouncedEmail, editingStaff, setError, clearErrors]);

  useEffect(() => {
    fetchRoles(debouncedRoleSearch);
  }, [debouncedRoleSearch]);

  useEffect(() => {
    setSubjectPage(1);
    fetchSubjects(debouncedSubjectSearch, 1);
  }, [debouncedSubjectSearch]);

  useEffect(() => {
    if (subjectPage > 1) {
      fetchSubjects(debouncedSubjectSearch, subjectPage);
    }
  }, [subjectPage]);

  return (
    <div className="flex flex-col gap-4 px-4 py-6">
      <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
        <div>
          <h2 className="text-2xl font-bold text-slate-800 flex items-center gap-2">
            <UserCog className="text-blue-600" /> Staff Management
          </h2>
          <p className="text-slate-500 text-sm mt-1">
            Add /Manage Staff Details & Permissions.
          </p>
        </div>
        <Button
          type="primary"
          icon={<Plus size={16} />}
          onClick={() => setIsModalOpen(true)}
        >
          Add New Staff
        </Button>
      </div>

      <Card className="shadow-sm border border-slate-200 rounded-xl">
        <div className="flex flex-wrap items-center gap-4 mb-4">
          <div className="w-full md:w-64">
            <Input
              placeholder={"Search staff, email..."}
              prefix={<Search size={16} className="text-slate-400" />}
              allowClear
              autoComplete="off"
              value={filterValues.search}
              onChange={(e) =>
                setFilterValues({ ...filterValues, search: e.target.value })
              }
            />
          </div>

          <Select
            placeholder="Verified Status"
            className="w-full md:w-40"
            allowClear
            value={filterValues.isVerified}
            onChange={(val) =>
              setFilterValues({ ...filterValues, isVerified: val })
            }
            options={[
              { label: "Verified", value: "true" },
              { label: "Pending", value: "false" },
            ]}
          />

          <Select
            placeholder="Filter by Role"
            className="w-full md:w-48"
            allowClear
            value={filterValues.roleId}
            onChange={(val) =>
              setFilterValues({ ...filterValues, roleId: val })
            }
            options={options.roles}
          />

          <Select
            placeholder="Filter by Subject"
            className="w-full md:w-48"
            allowClear
            showSearch
            filterOption={false}
            onSearch={(val) => setSubjectSearch(val)}
            onPopupScroll={(e) => {
              const target = e.target as HTMLElement;
              if (
                Math.ceil(target.scrollTop + target.offsetHeight) >= target.scrollHeight &&
                hasMoreSubjects &&
                !loadingSubjects
              ) {
                setSubjectPage((prev) => prev + 1);
              }
            }}
            value={filterValues.subjectId}
            onChange={(val) =>
              setFilterValues({ ...filterValues, subjectId: val })
            }
            options={options.subjects}
            loading={loadingSubjects}
          />

          <Button
            type="link"
            size="small"
            className="text-slate-500 hover:text-blue-600 p-0 h-auto"
            onClick={() => setFilterValues(filterInitial)}
          >
            Clear All
          </Button>

          <div className="ml-auto text-slate-500 text-sm">
            Total: <span className="font-semibold text-slate-800">{total}</span>
          </div>
        </div>

        <Table
          columns={columns}
          dataSource={staff}
          loading={loading}
          pagination={false}
          rowKey="id"
          scroll={{ x: 800 }}
          className="border border-slate-100 rounded-lg overflow-hidden"
        />

        <div className="flex justify-end mt-4">
          <Pagination
            current={page}
            total={total}
            pageSize={limit}
            onChange={(p, pageSize) => {
              setPage(p);
              setLimit(pageSize);
              fetchStaff(p, pageSize, filterValues);
            }}
            showSizeChanger
            showTotal={(total) => `Total ${total} items`}
          />
        </div>
      </Card>

      <Modal
        isOpen={isModalOpen}
        onClose={closeModal}
        title={editingStaff ? "Edit Staff" : "Add Staff"}
      >
        <Form layout="vertical" onFinish={handleSubmit(onFormSubmit)} autoComplete="off">
          <Row gutter={16}>
            <Col span={12}>
              <Form.Item
                label="First Name"
                validateStatus={errors.firstName ? "error" : ""}
                help={errors.firstName?.message}
                required
              >
                <Controller
                  name="firstName"
                  control={control}
                  render={({ field }) => (
                    <Input {...field} placeholder="First Name" />
                  )}
                />
              </Form.Item>
            </Col>

            <Col span={12}>
              <Form.Item
                label="Last Name"
                validateStatus={errors.lastName ? "error" : ""}
                help={errors.lastName?.message}
                required
              >
                <Controller
                  name="lastName"
                  control={control}
                  render={({ field }) => (
                    <Input {...field} placeholder="Last Name" />
                  )}
                />
              </Form.Item>
            </Col>
          </Row>

          <Row gutter={16}>
            <Col span={12}>
              <Form.Item
                label="Email"
                validateStatus={errors.email ? "error" : ""}
                help={errors.email?.message}
                required
              >
                <Controller
                  name="email"
                  control={control}
                  render={({ field }) => (
                    <Input
                      {...field}
                      autoComplete="off"
                      type="email"
                      placeholder="Email"
                      disabled={editingStaff !== null}
                    />
                  )}
                />
              </Form.Item>
            </Col>

            <Col span={12}>
              <Form.Item
                label="Phone"
                validateStatus={errors.phone ? "error" : ""}
                help={errors.phone?.message}
                required
              >
                <Controller
                  name="phone"
                  control={control}
                  rules={{
                    required: "Phone number is required",
                    pattern: {
                      value: /^[0-9]{10}$/,
                      message: "Phone number must be 10 digits",
                    },
                  }}
                  render={({ field }) => (
                    <Input
                      {...field}
                      type="text"
                      inputMode="numeric"
                      maxLength={10}
                      placeholder="Phone"
                      onChange={(e) => {
                        const value = e.target.value.replace(/\D/g, "");

                        field.onChange(value);

                        setValue("password", value);
                      }}
                    />
                  )}
                />
              </Form.Item>
            </Col>

            {/* <Col span={12}>
              <Form.Item
                label="Designation"
                validateStatus={errors.designation ? "error" : ""}
                help={errors.designation?.message}
                required
              >
                <Controller
                  name="designation"
                  control={control}
                  render={({ field }) => (
                    <Input {...field} type="text" placeholder="Designation" />
                  )}
                />
              </Form.Item>
            </Col> */}
            {!editingStaff && (
              <Col span={12}>
                <Form.Item
                  label="Password"
                  validateStatus={errors.password ? "error" : ""}
                  help={errors.password?.message}
                  required
                >
                  <Controller
                    name="password"
                    control={control}
                    render={({ field }) => (
                      <Input.Password
                        {...field}
                        type="password"
                        placeholder="Password"
                      />
                    )}
                  />
                </Form.Item>
              </Col>
            )}
          </Row>

          <Row gutter={16}>
            {/* <Col span={12}>
              <Form.Item
                label="Assign Exams"
                validateStatus={errors.exams ? "error" : ""}
                help={errors.exams?.message}
                required
              >
                <Controller
                  name="exams"
                  control={control}
                  render={({ field }) => (
                    <Select
                      mode="multiple"
                      value={field.value || []}
                      placeholder="Select Exams"
                      options={[
                        { value: "all", label: "Select All" },
                        ...options.exams,
                      ]}
                      onChange={(value) =>
                        handleSelectAll(value, field.onChange, options.exams)
                      }
                    />
                  )}
                />
              </Form.Item>
            </Col> */}
            <Col span={12}>
              <Form.Item
                label="Assign Role"
                validateStatus={errors.roleId ? "error" : ""}
                help={errors.roleId?.message}
                required
              >
                <Controller
                  name="roleId"
                  control={control}
                  render={({ field }) => (
                    <Select
                      {...field}
                      value={field.value || undefined}
                      placeholder="Select Role"
                      options={options.roles}
                      filterOption={false}
                      showSearch
                      allowClear
                      onClear={() => setValue("roleId", undefined)}
                      onSearch={(value) => {
                        setRoleSearch(value);
                      }}
                    />
                  )}
                />
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item
                label="Assign Subjects"
                validateStatus={errors.subjects ? "error" : ""}
                help={errors.subjects?.message}
                required
              >
                <Controller
                  name="subjects"
                  control={control}
                  render={({ field }) => (
                    <Select
                      mode="multiple"
                      value={field.value || []}
                      placeholder="Select Subjects"
                      options={
                        options.subjects.length > 0
                          ? [
                            { value: "all", label: "Select All" },
                            ...options.subjects,
                          ]
                          : []
                      }
                      onChange={(value) => {
                        handleSelectAll(
                          value as string[],
                          field.onChange,
                          options.subjects,
                        );
                      }}
                      filterOption={false}
                      allowClear
                      showSearch
                      onClear={() => setValue("subjects", [])}
                      onSearch={(value) => {
                        setSubjectSearch(value);
                      }}
                      onPopupScroll={(e) => {
                        const target = e.target as HTMLElement;
                        if (
                          Math.ceil(target.scrollTop + target.offsetHeight) >= target.scrollHeight &&
                          hasMoreSubjects &&
                          !loadingSubjects
                        ) {
                          setSubjectPage((prev) => prev + 1);
                        }
                      }}
                      loading={loadingSubjects}
                    />
                  )}
                />
              </Form.Item>
            </Col>
          </Row>

          <div className="flex justify-end gap-3 mb-0">
            <Button onClick={closeModal}>Cancel</Button>
            <Button type="primary" htmlType="submit" loading={isSubmitting}>
              Save
            </Button>
          </div>
        </Form>
      </Modal>
    </div>
  );
};

export default StaffManagement;
