import dayjs from "dayjs";
import toast from "react-hot-toast";
import { Search, Share2, Download, Loader2 } from "lucide-react";
import { API_Instance } from "@/api/axios.instance";
import { getAxiosErrorMessage } from "@/utils/index.utils";
import type { ColumnsType, TableProps } from "antd/es/table";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Card, Table, Tag, Pagination, Input, Select, Button, DatePicker, Empty, Skeleton } from "antd";

interface IAttemptRow {
  id: string;
  testTitle: string;
  subjectName: string;
  testType: string;
  obtainedMarks: number;
  totalMarks: number;
  totalQuestions: number;
  scorePercentage: number;
  createdAt: string;
  examName: string;
  examId: string;
}

const paginationInitial = { page: 1, limit: 10, total: 0, totalPages: 0 };
const filterInitial = {
  search: "",
  testType: undefined as string | undefined,
  subjectId: undefined as string | undefined,
  startDate: undefined as string | undefined,
  endDate: undefined as string | undefined,
};

const sortInitial = {
  sortBy: "date",
  sortOrder: "desc" as "asc" | "desc",
  isSortedByUser: false,
};

interface ResultsScoresTabProps {
  studentId: string;
  subjects: { id: string; subjectName: string }[];
  onStudentInfoLoaded?: (info: { name: string; email: string; phone: string; examName: string; examId: string }) => void;
}

const ResultsScoresTab: React.FC<ResultsScoresTabProps> = ({ studentId, subjects, onStudentInfoLoaded }) => {
  const [attempts, setAttempts] = useState<IAttemptRow[]>([]);
  const [loading, setLoading] = useState(false);
  const [exportLoading, setExportLoading] = useState(false);
  const [pagination, setPagination] = useState(paginationInitial);
  const [filterValues, setFilterValues] = useState(filterInitial);
  const [sortValues, setSortValues] = useState(sortInitial);
  const [debouncedSearch, setDebouncedSearch] = useState("");

  const [examList, setExamList] = useState<{ id: string; examName: string }[]>([]);
  const [examFilter, setExamFilter] = useState<string | undefined>(undefined);
  const [examPage, setExamPage] = useState(1);
  const [hasMoreExams, setHasMoreExams] = useState(true);
  const [examLoading, setExamLoading] = useState(false);
  const [examSearch, setExamSearch] = useState("");
  const [debouncedExamSearch, setDebouncedExamSearch] = useState("");

  const [subjectsList, setSubjectsList] = useState<{ id: string; subjectName: string; isShared?: boolean; sharedInstitutionName?: string }[]>([]);
  const [subjectSearchText, setSubjectSearchText] = useState("");
  const [debouncedSubjectSearch, setDebouncedSubjectSearch] = useState("");
  const [subjectPage, setSubjectPage] = useState(1);
  const [hasMoreSubjects, setHasMoreSubjects] = useState(true);
  const [loadingSubjects, setLoadingSubjects] = useState(false);

  useEffect(() => {
    const t = setTimeout(() => setDebouncedExamSearch(examSearch), 400);
    return () => clearTimeout(t);
  }, [examSearch]);

  const fetchExamsList = useCallback(async (search: string, page: number) => {
    setExamLoading(true);
    try {
      const res = await API_Instance.get("/exams", { params: { search, page, limit: 10 } });
      const items: { id: string; examName: string }[] = res.data?.data || [];
      setExamList((prev) => (page === 1 ? items : [...prev, ...items]));
      setHasMoreExams(items.length === 10);
    } catch {
      console.error("Failed to fetch exams");
    } finally {
      setExamLoading(false);
    }
  }, []);

  useEffect(() => {
    setExamPage(1);
    fetchExamsList(debouncedExamSearch, 1);
  }, [debouncedExamSearch, fetchExamsList]);

  useEffect(() => {
    if (examPage > 1) fetchExamsList(debouncedExamSearch, examPage);
  }, [examPage, debouncedExamSearch, fetchExamsList]);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedSubjectSearch(subjectSearchText), 500);
    return () => clearTimeout(timer);
  }, [subjectSearchText]);

  const fetchSubjectsList = useCallback(async (search = "", page = 1) => {
    setLoadingSubjects(true);
    try {
      const res = await API_Instance.get("/subjects", {
        params: { search, page, limit: 10, includeShared: "true" }
      });
      const newSubjects = res.data?.data || [];
      setSubjectsList((prev) => (page === 1 ? newSubjects : [...prev, ...newSubjects]));
      setHasMoreSubjects(newSubjects.length === 10);
    } catch (e) {
      console.error("Failed to fetch subjects list", e);
    } finally {
      setLoadingSubjects(false);
    }
  }, []);

  useEffect(() => {
    if (filterValues.testType === "PracticeTest") {
      setSubjectPage(1);
      fetchSubjectsList(debouncedSubjectSearch, 1);
    }
  }, [debouncedSubjectSearch, filterValues.testType, fetchSubjectsList]);

  useEffect(() => {
    if (subjectPage > 1 && filterValues.testType === "PracticeTest") {
      fetchSubjectsList(debouncedSubjectSearch, subjectPage);
    }
  }, [subjectPage, debouncedSubjectSearch, filterValues.testType, fetchSubjectsList]);

  const visibleSubjects = useMemo(() => {
    const list = [...subjectsList];
    if (filterValues.subjectId && !list.some((s) => s.id === filterValues.subjectId)) {
      const activeSubject = subjects.find((s) => s.id === filterValues.subjectId);
      if (activeSubject) {
        list.unshift(activeSubject);
      }
    }
    return list;
  }, [subjectsList, filterValues.subjectId, subjects]);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedSearch(filterValues.search), 600);
    return () => clearTimeout(timer);
  }, [filterValues.search]);

  const fetchPerformance = useCallback(
    async (page = 1, limit = 10, sortBy = sortValues.sortBy, sortOrder = sortValues.sortOrder) => {
      if (!studentId) return;
      setLoading(true);
      try {
        const params: any = {
          page,
          limit,
          search: debouncedSearch,
          testType: filterValues.testType,
          subjectId: filterValues.testType === "PracticeTest" ? filterValues.subjectId : undefined,
          startDate: filterValues.startDate || undefined,
          endDate: filterValues.endDate || undefined,
          examId: examFilter || undefined,
          sortBy,
          sortOrder,
        };
        Object.keys(params).forEach((k) => params[k] === undefined && delete params[k]);

        const res = await API_Instance.get(`/reports/students/${studentId}/performance`, { params });

        if (onStudentInfoLoaded && res.data.student) {
          onStudentInfoLoaded(res.data.student);
        }

        setAttempts(res.data.data || []);
        setPagination({
          page: res.data.meta.page,
          limit: res.data.meta.limit,
          total: res.data.meta.total,
          totalPages: res.data.meta.totalPages,
        });
      } catch (e) {
        toast.error(getAxiosErrorMessage(e));
      } finally {
        setLoading(false);
      }
    },
    [studentId, debouncedSearch, filterValues.testType, filterValues.subjectId, filterValues.startDate, filterValues.endDate, examFilter, onStudentInfoLoaded, sortValues.sortBy, sortValues.sortOrder]
  );

  const handleExportPDF = async () => {
    if (attempts.length === 0) {
      toast.error("No data available to export.");
      return;
    }
    setExportLoading(true);
    try {
      const params: any = {
        search: debouncedSearch || undefined,
        testType: filterValues.testType,
        subjectId: filterValues.testType === "PracticeTest" ? filterValues.subjectId : undefined,
        startDate: filterValues.startDate || undefined,
        endDate: filterValues.endDate || undefined,
        examId: examFilter || undefined,
        sortBy: sortValues.sortBy,
        sortOrder: sortValues.sortOrder,
      };
      Object.keys(params).forEach((k) => params[k] === undefined && delete params[k]);
      const res = await API_Instance.get(`/reports/students/${studentId}/performance-pdf`, {
        params,
        responseType: "blob",
      });
      const blobUrl = window.URL.createObjectURL(new Blob([res.data], { type: "application/pdf" }));
      const link = document.createElement("a");
      link.href = blobUrl;
      link.setAttribute("download", `Student_Performance_${dayjs().format("DD-MM-YYYY")}.pdf`);
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(blobUrl);
      toast.success("PDF downloaded successfully.");
    } catch (error) {
      toast.error(getAxiosErrorMessage(error));
    } finally {
      setExportLoading(false);
    }
  };

  useEffect(() => {
    fetchPerformance(1, pagination.limit);
  }, [fetchPerformance]);

  const handleTableChange: TableProps<IAttemptRow>["onChange"] = (
    _,
    __,
    sorter: any
  ) => {
    let newSortBy = "date";
    let newSortOrder: "asc" | "desc" = "desc";
    let userInteracted = false;

    if (sorter && sorter.order) {
      userInteracted = true;
      newSortOrder = sorter.order === "ascend" ? "asc" : "desc";
      newSortBy = (sorter.column?.key || sorter.field || sorter.key) as string;
    }

    setSortValues({ sortBy: newSortBy, sortOrder: newSortOrder, isSortedByUser: userInteracted });
    fetchPerformance(1, pagination.limit, newSortBy, newSortOrder);
  };

  const columns: ColumnsType<IAttemptRow> = [
    {
      title: "Exam",
      dataIndex: "examName",
      key: "examName",
      width: "15%",
      render: (text) => (
        <span className="rounded-full px-2 m-0 text-medium">
          {text}
        </span>
      ),
    },
    {
      title: "Test Type",
      dataIndex: "testType",
      key: "testType",
      width: "18%",
      render: (type, record) => {
        const map: Record<string, { label: string; color: string }> = {
          PracticeTest: { label: "Practice Test", color: "blue" },
          MockTest: { label: "Mock Test", color: "purple" },
          OldQuestionPaper: { label: "PYQ", color: "green" },
        };
        const info = map[type] || { label: type, color: "default" };
        return (
          <div className="flex flex-col gap-1 items-start">
            <Tag color={info.color} className="uppercase rounded-full px-3 m-0 font-medium">
              {info.label}
            </Tag>
            {type === "PracticeTest" && record.subjectName && (
              <Tag color="orange" className="uppercase rounded-full font-medium px-3 m-0 border border-orange-100 bg-orange-50">
                {record.subjectName}
              </Tag>
            )}
          </div>
        );
      },
    },
    {
      title: "Test Title",
      dataIndex: "testTitle",
      key: "testTitle",
      width: "20%",
      sorter: true,
      sortOrder: sortValues.sortBy === "testTitle" ? (sortValues.sortOrder === "asc" ? "ascend" : "descend") : undefined,
      render: (text) => <span className="font-semibold text-slate-700">{text}</span>,
    },
    {
      title: "Date",
      dataIndex: "createdAt",
      key: "date",
      width: "18%",
      sorter: true,
      sortOrder: sortValues.sortBy === "date" && sortValues.isSortedByUser
        ? (sortValues.sortOrder === "asc" ? "ascend" : "descend")
        : undefined,
      render: (date) => (
        <span className="text-xs text-slate-500">{dayjs(date).format("DD MMM YYYY, hh:mm A")}</span>
      ),
    },
    {
      title: "Score",
      key: "score",
      width: "12%",
      sorter: true,
      sortOrder: sortValues.sortBy === "score" ? (sortValues.sortOrder === "asc" ? "ascend" : "descend") : undefined,
      render: (_, record) => (
        <div className="flex items-center gap-1 font-medium">
          <span className="text-blue-600">{record.obtainedMarks}</span>
          <span className="text-slate-400">/</span>
          <span className="text-slate-600">{record.totalMarks}</span>
        </div>
      ),
    },
    {
      title: "Percentage",
      key: "percentage",
      width: "12%",
      sorter: true,
      sortOrder: sortValues.sortBy === "percentage" ? (sortValues.sortOrder === "asc" ? "ascend" : "descend") : undefined,
      render: (_, record) => {
        const pct = record.totalMarks > 0 ? ((record.obtainedMarks / record.totalMarks) * 100).toFixed(1) : "0.0";
        const isPass = parseFloat(pct) >= 40;
        return (
          <Tag color={isPass ? "success" : "error"} className="font-semibold rounded-full px-3">
            {pct}%
          </Tag>
        );
      },
    },
  ];

  return (
    <div className="flex flex-col gap-6">
      <Card className="shadow-sm border border-slate-200 rounded-xl">
        <div className={`grid grid-cols-1 sm:grid-cols-2 ${filterValues.testType === "PracticeTest" ? "lg:grid-cols-5" : "lg:grid-cols-4"} gap-4 p-4 bg-slate-50 rounded-xl border border-slate-100 items-center`}>
          <div className="w-full">
            <Input
              placeholder="Search test title..."
              prefix={<Search size={16} className="text-slate-400" />}
              allowClear
              value={filterValues.search}
              onChange={(e) => setFilterValues((prev) => ({ ...prev, search: e.target.value }))}
            />
          </div>

          <Select
            placeholder="Select Exam"
            allowClear
            showSearch
            filterOption={false}
            value={examFilter}
            onChange={(val) => setExamFilter(val)}
            onSearch={(val) => setExamSearch(val)}
            onDropdownVisibleChange={(open) => { if (!open) setExamSearch(""); }}
            loading={examLoading}
            options={examList.map((e) => ({ label: e.examName, value: e.id }))}
            onPopupScroll={(e) => {
              const target = e.target as HTMLElement;
              if (target.scrollTop + target.clientHeight >= target.scrollHeight - 20 && hasMoreExams && !examLoading) {
                setExamPage((prev) => prev + 1);
              }
            }}
            className="w-full"
          />

          <Select
            placeholder="Test Type"
            allowClear
            value={filterValues.testType}
            onChange={(val) => setFilterValues((prev) => ({ ...prev, testType: val, subjectId: undefined }))}
            options={[
              { label: "Practice Test", value: "PracticeTest" },
              { label: "Mock Test", value: "MockTest" },
              { label: "PYQ Test", value: "OldQuestionPaper" },
            ]}
          />

          {filterValues.testType === "PracticeTest" && (
            <Select
              placeholder="Select Subject"
              allowClear
              showSearch
              filterOption={false}
              onSearch={(val) => setSubjectSearchText(val)}
              onDropdownVisibleChange={(open) => {
                if (!open) setSubjectSearchText("");
              }}
              onPopupScroll={(e) => {
                const target = e.target as HTMLElement;
                const currentScrollPosition = target.scrollTop + target.clientHeight;
                const scrollThreshold = target.scrollHeight - 15;

                if (currentScrollPosition >= scrollThreshold && hasMoreSubjects && !loadingSubjects) {
                  setSubjectPage((prev) => prev + 1);
                }
              }}
              value={filterValues.subjectId}
              onChange={(val) => setFilterValues((prev) => ({ ...prev, subjectId: val }))}
              optionLabelProp="name"
              options={visibleSubjects.map((s) => ({ 
                name: s.subjectName,
                label: (
                  <div className="flex items-center gap-2">
                    {s.isShared && (
                      <div className="flex items-center text-blue-600" title={`Shared by Exam Infra`}>
                        <Share2 size={12} className="text-purple-500 flex-shrink-0" />
                      </div>
                    )}
                    <span className="font-medium text-slate-700 truncate">{s.subjectName}</span>
                  </div>
                ), 
                value: s.id,
                title: s.subjectName
              }))}
              loading={loadingSubjects}
              className="w-full"
            />
          )}

          <div className="sm:col-span-2 lg:col-span-1 flex items-center justify-between gap-2 border border-slate-300 rounded-lg px-2 bg-white h-[32px] w-full">
            <DatePicker
              placeholder="From Date"
              format="YYYY-MM-DD"
              className="border-none p-0 shadow-none flex-1 text-xs"
              value={filterValues.startDate ? dayjs(filterValues.startDate) : null}
              disabledDate={(current) => {
                const isFuture = current && current > dayjs().endOf('day');
                return isFuture || (filterValues.endDate ? current > dayjs(filterValues.endDate).endOf('day') : false);
              }}
              onChange={(date) => setFilterValues((prev) => ({ ...prev, startDate: date ? date.format("YYYY-MM-DD") : undefined }))}
            />
            <span className="text-slate-300 text-xs px-1">to</span>
            <DatePicker
              placeholder="To Date"
              format="YYYY-MM-DD"
              className="border-none p-0 shadow-none flex-1 text-xs"
              value={filterValues.endDate ? dayjs(filterValues.endDate) : null}
              disabledDate={(current) => {
                const isFuture = current && current > dayjs().endOf('day');
                return isFuture || (filterValues.startDate ? current < dayjs(filterValues.startDate).startOf('day') : false);
              }}
              onChange={(date) => setFilterValues((prev) => ({ ...prev, endDate: date ? date.format("YYYY-MM-DD") : undefined }))}
            />
          </div>
        </div>

        <div className="flex justify-end mt-3">
          <Button
            type="link"
            size="small"
            className="text-slate-500 hover:text-blue-600 p-0 h-auto font-medium"
            onClick={() => {
              setFilterValues(filterInitial);
              setSortValues(sortInitial);
              setSubjectSearchText("");
              setSubjectPage(1);
            }}
          >
            Clear All Filters
          </Button>
        </div>
      </Card>

      <Card className="shadow-sm border border-slate-200 rounded-xl">
        {loading && attempts.length === 0 ? (
          <div className="p-8">
            <Skeleton active paragraph={{ rows: 5 }} />
          </div>
        ) : attempts.length === 0 ? (
          <Empty description="No test attempts found" className="py-16" />
        ) : (
          <>
            <div className="flex justify-between items-center mb-4">
              <div className="text-slate-500 text-sm font-medium bg-slate-100 px-3 py-1 rounded-md border border-slate-200">
                Total : <span className="font-bold text-slate-800">{pagination.total}</span>
              </div>
              <Button
                type="primary"
                disabled={exportLoading}
                onClick={handleExportPDF}
                className="bg-blue-600 hover:bg-blue-700 hover:text-white flex items-center gap-2 rounded-lg font-medium"
                icon={exportLoading ? <Loader2 size={16} className="animate-spin" /> : <Download size={16} />}
              >
                {exportLoading ? "Generating PDF..." : "Export PDF"}
              </Button>
            </div>
            <Table
              columns={columns}
              dataSource={attempts}
              loading={loading}
              rowKey="id"
              pagination={false}
              scroll={{ x: 800 }}
              onChange={handleTableChange}
              className="border border-slate-100 rounded-lg overflow-hidden"
            />
            <div className="flex justify-end mt-4">
              <Pagination
                current={pagination.page}
                total={pagination.total}
                pageSize={pagination.limit}
                onChange={(page, pageSize) => {
                  setPagination((prev) => ({ ...prev, page, limit: pageSize }));
                  fetchPerformance(page, pageSize);
                }}
                showSizeChanger
                showTotal={(total) => `Total ${total} attempts`}
              />
            </div>
          </>
        )}
      </Card>
    </div>
  );
};

export default ResultsScoresTab;