﻿import { useEffect, useState } from "react";
import {
  Button,
  Form,
  Input,
  Pagination,
  Popconfirm,
  Spin,
  Select,
  Upload,
  DatePicker,
} from "antd";
import {
  Plus,
  Edit,
  Trash2,
  FileText,
  Download,
  UploadCloud,
  Bell,
  Search,
} 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 { API_Instance } from "../../api/axios.instance";
import API_Constants from "../../constants/api.constants";
import toast from "react-hot-toast";
import Modal from "@/components/shared/Modal";
import { IPagination, INotification } from "@/types";
import { buildQuery, MAX_FILE_SIZE, MAX_FILES } from "@/utils/index.utils";
import type { UploadFile } from "antd/es/upload/interface";
import dayjs from "dayjs";
import { useDebounce } from "@/hooks/useDebounce";

type NotificationFormValues = {
  exam: string;
  title: string;
  description: string;
  date: any;
};

interface IExamOption {
  label: string;
  value: string;
}

const schema = yup.object({
  exam: yup.string().required("Exam is required"),
  title: yup.string().required("Title is required"),
  description: yup.string().required("Description is required"),
  date: yup.mixed().required("Date is required"),
});

const initialPagination: IPagination = {
  page: 1,
  limit: 10,
  total: 0,
  totalPages: 0,
};

export default function NotificationTab() {
  const [notificationList, setNotificationList] = useState<INotification[]>([]);
  const [exams, setExams] = useState<IExamOption[]>([]);
  const [loading, setLoading] = useState(false);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [editingNotification, setEditingNotification] = useState<INotification | null>(null);
  const [pagination, setPagination] = useState(initialPagination);
  const [fileList, setFileList] = useState<UploadFile[]>([]);
  const [searchText, setSearchText] = useState("");
  const [examSearch, setExamSearch] = useState("");
  const [examLoading, setExamLoading] = useState(false);

  const [examPage, setExamPage] = useState(1);
  const [hasMoreExams, setHasMoreExams] = useState(true);

  const debounceText = useDebounce(searchText, 600);
  const debounceExamSearch = useDebounce(examSearch, 600);

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

  const {
    control,
    handleSubmit,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<NotificationFormValues>({
    resolver,
    defaultValues: { exam: "", title: "", description: "", date: dayjs() },
  });

  const fetchExams = async (search = "", page = 1) => {
    setExamLoading(true);
    try {
      const res = await API_Instance.get(API_Constants.exams, {
        params: {
          search,
          page,
          limit: 10,
        },
      });

      const newExams = (res?.data?.data || [])
        .map((exam: any) => ({
          label: exam.examName,
          value: exam.id,
        }))
        .sort((a: any, b: any) => a.label.localeCompare(b.label));

      setExams((prev) => (page === 1 ? newExams : [...prev, ...newExams]));
      setHasMoreExams(newExams.length === 10);
    } catch (err) {
      toast.error("Failed to fetch exams");
    } finally {
      setExamLoading(false);
    }
  };

  const fetchNotifications = async (
    page: number = initialPagination.page,
    limit: number = initialPagination.limit,
    filters: any,
  ) => {
    setLoading(true);
    const query = buildQuery(filters, page, limit);
    try {
      const res = await API_Instance.get(
        API_Constants.notifications + `?${query}`,
      );
      setNotificationList(res.data.data);
      setPagination(res.data.meta);
    } catch (err) {
      toast.error("Failed to fetch notifications");
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchNotifications(initialPagination.page, initialPagination.limit, {});
  }, []);

  useEffect(() => {
    if (editingNotification) {
      reset({
        exam: editingNotification.exam,
        title: editingNotification.title,
        description: editingNotification.description,
        date: dayjs(editingNotification.date),
      });
      if (editingNotification.files && editingNotification.files.length > 0) {
        setFileList(
          editingNotification.files.map((file, index) => ({
            uid: index.toString(),
            name: file.split("/").pop() || `file_${index}`,
            status: "done",
            url: file,
          })),
        );
      } else {
        setFileList([]);
      }
    } else {
      reset({ exam: "", title: "", description: "", date: dayjs() });
      setFileList([]);
    }
  }, [editingNotification, reset]);

  const openModal = (notification: INotification | null = null) => {
    setEditingNotification(notification);
    setIsModalOpen(true);
  };

  const closeModal = () => {
    setEditingNotification(null);
    setIsModalOpen(false);
    setFileList([]);
    reset();
  };

  const onFormSubmit: SubmitHandler<NotificationFormValues> = async (data) => {
    try {
      const formData = new FormData();
      formData.append("exam", data.exam);
      formData.append("title", data.title);
      formData.append("description", data.description);
      formData.append("date", data.date.toISOString());

      fileList.forEach((file) => {
        if (file.originFileObj) {
          formData.append("files", file.originFileObj);
        } else if (file.url) {
          formData.append("existingFiles", file.url);
        } else if (file instanceof File) {
          formData.append("files", file);
        }
      });

      if (editingNotification) {
        await API_Instance.put(
          `${API_Constants.notifications}/${editingNotification.id}`,
          formData,
          { headers: { "Content-Type": "multipart/form-data" } },
        );
        toast.success("Notification updated successfully");
      } else {
        await API_Instance.post(API_Constants.notifications, formData, {
          headers: { "Content-Type": "multipart/form-data" },
        });
        toast.success("Notification added successfully");
      }
      fetchNotifications(pagination.page, pagination.limit, { search: searchText });
      closeModal();
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "Failed to save notification");
    }
  };

  const handleDelete = async (notification: INotification) => {
    try {
      await API_Instance.delete(`${API_Constants.notifications}/${notification.id}`);
      toast.success("Notification deleted successfully");
      fetchNotifications(pagination.page, pagination.limit, { search: searchText });
    } catch (err) {
      toast.error("Failed to delete notification");
    }
  };

  useEffect(() => {
    fetchNotifications(1, pagination.limit, { search: searchText });
  }, [debounceText]);

  useEffect(() => {
    setExamPage(1);
    fetchExams(debounceExamSearch, 1);
  }, [debounceExamSearch]);

  useEffect(() => {
    if (examPage > 1) {
      fetchExams(debounceExamSearch, examPage);
    }
  }, [examPage]);

  return (
    <div className="flex flex-col gap-4">
      <div className="flex flex-col md:flex-row justify-between items-center gap-4 mb-4">
        <div className="w-full md:w-72">
          <Input
            placeholder="Search notifications..."
            prefix={<Search size={16} className="text-slate-400" />}
            allowClear
            value={searchText}
            onChange={(e) => setSearchText(e.target.value)}
          />
        </div>
        <div className="flex items-center gap-4">
          <div className="text-slate-500 text-sm">
            Total:{" "}
            <span className="font-semibold text-slate-800">
              {pagination.total}
            </span>
          </div>
          <Button
            type="primary"
            icon={<Plus size={16} />}
            className="!bg-brand-green hover:!bg-brand-green/80 flex items-center gap-2"
            onClick={() => openModal()}
          >
            Add New Notification
          </Button>
        </div>
      </div>

      {loading ? (
        <div className="h-64 flex items-center justify-center">
          <Spin />
        </div>
      ) : notificationList.length === 0 ? (
        <div className="h-64 flex flex-col items-center justify-center text-slate-400 border-2 border-dashed border-slate-100 rounded-xl">
          <Bell size={48} className="text-slate-200 mb-2" />
          <p>
            {searchText
              ? "No notifications found matching your search"
              : "No notifications available"}
          </p>
        </div>
      ) : (
        <div className="flex flex-col gap-4">
          {notificationList.map((notification) => (
            <div
              key={notification.id}
              className="group bg-white p-6 rounded-xl border border-slate-200 hover:border-blue-200 hover:shadow-md transition-all relative overflow-hidden"
            >
              <div className="flex justify-between items-start gap-4">
                <div className="flex gap-4">
                  <div className="bg-blue-50 p-3 rounded-xl group-hover:bg-blue-100 transition-colors">
                    <Bell className="h-6 w-6 text-blue-600" />
                  </div>
                  <div>
                    <h3 className="text-lg font-bold text-slate-800 flex items-center gap-3">
                      {notification.title}
                    </h3>
                    <div className="flex items-center gap-2 mt-1">
                      <span className="text-xs font-semibold text-blue-500 bg-blue-50/50 px-2 py-0.5 rounded">
                        {notification.examName}
                      </span>
                      <span className="text-slate-400 text-xs flex items-center gap-1">
                        {dayjs(notification.date).format("DD MMM, YYYY")}
                      </span>
                    </div>
                    <p className="text-slate-500 text-sm mt-3 max-w-2xl">
                      {notification.description}
                    </p>

                    {notification.files && notification.files.length > 0 && (
                      <div className="flex flex-wrap gap-2 mt-4">
                        {notification.files.map((file, idx) => (
                          <a
                            key={idx}
                            href={file}
                            target="_blank"
                            rel="noopener noreferrer"
                            className="flex items-center gap-2 bg-slate-50 hover:bg-blue-50 px-3 py-1.5 rounded-lg border border-slate-100 hover:border-blue-100 text-slate-600 hover:text-blue-600 transition-all text-xs font-medium"
                          >
                            <Download size={14} className="text-blue-500" />
                            Attachment {idx + 1}
                          </a>
                        ))}
                      </div>
                    )}
                  </div>
                </div>

                <div className="flex flex-col gap-2">
                  <div className="flex items-center gap-1">
                    <button
                      onClick={() => openModal(notification)}
                      className="p-2 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all"
                      title="Edit"
                    >
                      <Edit size={18} />
                    </button>
                    <Popconfirm
                      title="Delete Notification"
                      description="Are you sure you want to delete this notification?"
                      onConfirm={() => handleDelete(notification)}
                      okText="Yes, Delete"
                      cancelText="Cancel"
                      okButtonProps={{ danger: true }}
                    >
                      <button
                        className="p-2 text-slate-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-all"
                        title="Delete"
                      >
                        <Trash2 size={18} />
                      </button>
                    </Popconfirm>
                  </div>
                  <span className="text-[10px] text-slate-400 font-mono text-right">
                    ID: {notification.id.slice(-6).toUpperCase()}
                  </span>
                </div>
              </div>
            </div>
          ))}

          <div className="flex justify-end mt-4">
            <Pagination
              current={pagination.page || initialPagination.page}
              total={pagination.total || initialPagination.total}
              pageSize={pagination.limit || initialPagination.limit}
              onChange={(p, pageSize) => {
                setPagination((prev) => ({
                  ...prev,
                  page: p,
                  limit: pageSize,
                }));
                fetchNotifications(p, pageSize, { search: searchText });
              }}
              showSizeChanger
              showTotal={(total) => `Total ${total} items`}
            />
          </div>
        </div>
      )}
      <Modal
        isOpen={isModalOpen}
        onClose={closeModal}
        title={editingNotification ? "Edit Notification" : "Add Notification"}
      >
        <Form layout="vertical" onFinish={handleSubmit(onFormSubmit)}>
          <Form.Item
            label={
              <>
                Exam <span className="text-red-500 ps-1">*</span>
              </>
            }
            validateStatus={errors.exam ? "error" : ""}
            help={errors.exam?.message}
          >
            <Controller
              name="exam"
              control={control}
              render={({ field }) => (
                <Select
                  {...field}
                  placeholder="Select exam"
                  showSearch
                  allowClear
                  filterOption={false}
                  onSearch={(val) => setExamSearch(val)}
                  onPopupScroll={(e) => {
                    const target = e.target as HTMLElement;
                    if (
                      Math.ceil(target.scrollTop + target.offsetHeight) >= target.scrollHeight &&
                      hasMoreExams &&
                      !examLoading
                    ) {
                      setExamPage((prev) => prev + 1);
                    }
                  }}
                  loading={examLoading}
                  options={exams}
                />
              )}
            />
          </Form.Item>

          <Form.Item
            label={
              <>
                Title <span className="text-red-500 ps-1">*</span>
              </>
            } 
            validateStatus={errors.title ? "error" : ""}
            help={errors.title?.message}
          >
            <Controller
              name="title"
              control={control}
              render={({ field }) => (
                <Input {...field} placeholder="Enter title" />
              )}
            />
          </Form.Item>

          <Form.Item
            label={
              <>
                Description <span className="text-red-500 ps-1">*</span>
              </>
            }
            validateStatus={errors.description ? "error" : ""}
            help={errors.description?.message}
          >
            <Controller
              name="description"
              control={control}
              render={({ field }) => (
                <Input.TextArea
                  {...field}
                  placeholder="Enter description"
                  rows={3}
                />
              )}
            />
          </Form.Item>

          <Form.Item
            label={
              <>
                Date <span className="text-red-500 ps-1">*</span>
              </>
            }
            validateStatus={errors.date ? "error" : ""}
            help={errors.date?.message as string}
          >
            <Controller
              name="date"
              control={control}
              render={({ field }) => (
                <DatePicker {...field} style={{ width: "100%" }} maxDate={dayjs()} />
              )}
            />
          </Form.Item>

          <Form.Item label="Attachments (PDF, Max 5 files allowed)">
            <Upload
              fileList={fileList}
              accept=".pdf"
              multiple
              beforeUpload={(file) => {
                const isPDF = file.type === "application/pdf";
                if (!isPDF) {
                  toast.error("You can only upload PDF files!");
                  return Upload.LIST_IGNORE;
                }
                if (file.size > MAX_FILE_SIZE) {
                  toast.error("File size must be less than 5MB");
                  return Upload.LIST_IGNORE;
                }
                if (fileList.length >= MAX_FILES) {
                  toast.error("Max 5 files allowed");
                  return Upload.LIST_IGNORE;
                }
                setFileList((prev) => [...prev, file as any]);
                return false;
              }}
              onRemove={(file) => {
                setFileList((prev) => prev.filter((f) => f.uid !== file.uid));
              }}
              maxCount={MAX_FILES}
            >
              <Button icon={<UploadCloud className="h-4 w-4" />}>
                Upload Files
              </Button>
            </Upload>
          </Form.Item>

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

