import dayjs from "dayjs";
import toast from "react-hot-toast";
import { Difficulty } from "@/types";
import { useNavigate } from "react-router-dom";
import { useDebounce } from "@/hooks/useDebounce";
import React, { useEffect, useState } from "react";
import { API_Instance } from "../../api/axios.instance";
import API_Constants from "../../constants/api.constants";
import ROUTE_CONSTANTS from "@/constants/route.constants";
import { AccordionRow } from "@/components/shared/Accordion";
import { getAxiosErrorMessage, difficultyColor } from "@/utils/index.utils";
import { Card, Input, Popconfirm, Spin, Empty, Pagination, Tooltip, Select } from "antd";
import { RotateCcw, Search, Pencil, Trash2, ChevronDown, ChevronRight, ClipboardList, Clock, Info, CheckCircle, Link, Share2 } from "lucide-react";

interface PaginationState {
  page: number;
  limit: number;
  total: number;
  totalPages: number;
}

interface SubjectOption {
  id: string;
  subjectName: string;
  isShared?: boolean;
  sharedInstitutionName?: string | null;
}

const paginationInitial: PaginationState = {
  page: 1,
  limit: 10,
  total: 0,
  totalPages: 0,
};

const TestTree: React.FC = () => {
  const [loading, setLoading] = useState<boolean>(false);
  const [search, setSearch] = useState<string>("");
  const [tests, setTests] = useState<any[]>([]);
  const [pagination, setPagination] = useState<PaginationState>(paginationInitial);
  const debouncedSearch = useDebounce(search, 600);
  const navigate = useNavigate();

  const [subjects, setSubjects] = useState<SubjectOption[]>([]);
  const [selectedSubjectId, setSelectedSubjectId] = useState<string | undefined>(undefined);
  const [subjectsLoading, setSubjectsLoading] = useState<boolean>(false);
  const [subjectPage, setSubjectPage] = useState<number>(1);
  const [hasMoreSubjects, setHasMoreSubjects] = useState<boolean>(true);

  const [openTestId, setOpenTestId] = useState<string | null>(null);
  const [openQuestionId, setOpenQuestionId] = useState<string | null>(null);
  const [questions, setQuestions] = useState<any[]>([]);
  const [questionPagination, setQuestionPagination] = useState<PaginationState>(paginationInitial);
  const [questionsLoading, setQuestionsLoading] = useState<boolean>(false);
  const [questionSearch, setQuestionSearch] = useState<string>("");
  const debouncedQuestionSearch = useDebounce(questionSearch, 600);

  const fetchSubjects = async (page = 1, append = false) => {
    if (subjectsLoading) return;
    setSubjectsLoading(true);
    try {
      const res = await API_Instance.get(API_Constants.subjects || "/subjects", {
        params: { page, limit: 10, includeShared: true },
      });
      
      const fetchedData = res.data.data || res.data || [];
      const meta = res.data.meta;
      
      setSubjects((prev) => (append ? [...prev, ...fetchedData] : fetchedData));
      setSubjectPage(page);

      if (meta) {
        setHasMoreSubjects(page < Number(meta.totalPages));
      } else {
        setHasMoreSubjects(fetchedData.length === 10);
      }
    } catch (err) {
      console.error("Failed to load subjects options", err);
    } finally {
      setSubjectsLoading(false);
    }
  };

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

  const handleSubjectPopupScroll = (e: React.UIEvent<HTMLDivElement>) => {
    const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
    
    if (scrollHeight - scrollTop <= clientHeight + 10) {
      if (hasMoreSubjects && !subjectsLoading) {
        fetchSubjects(subjectPage + 1, true);
      }
    }
  };

  const fetchTests = async (page = 1, limit = 10, currentSubjectId = selectedSubjectId) => {
    setLoading(true);
    try {
      const res = await API_Instance.get(API_Constants.tests, {
        params: {
          page,
          limit,
          search: debouncedSearch,
          subjectId: currentSubjectId || undefined
        },
      });
      setTests(res.data.data || []);

      if (res.data.meta) {
        setPagination({
          page: Number(res.data.meta.page),
          limit: Number(res.data.meta.limit),
          total: Number(res.data.meta.total),
          totalPages: Number(res.data.meta.totalPages),
        });
      } else {
        setPagination({
          page: Number(page),
          limit: Number(limit),
          total: Number(res.data.data?.length || 0),
          totalPages: 1,
        });
      }
    } catch (err) {
      toast.error(getAxiosErrorMessage(err));
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchTests(1, pagination.limit, selectedSubjectId);
  }, [debouncedSearch, selectedSubjectId]);

  const handleDelete = async (id: string) => {
    try {
      await API_Instance.delete(`${API_Constants.tests}/${id}`);
      toast.success("Test deleted successfully");
      fetchTests(pagination.page, pagination.limit, selectedSubjectId);
    } catch (error: any) {
      toast.error(getAxiosErrorMessage(error));
    }
  };

  const getQuestions = async (page = 1, limit = 10, testId: string, qSearch = "", totalQuestionsFallback = 0) => {
    if (!testId) return;
    setQuestionsLoading(true);
    try {
      const response = await API_Instance.get(
        `${API_Constants.tests}/questions/${testId}`,
        { params: { page, limit, search: qSearch } }
      );
      setQuestions(response.data.questions || []);

      const metaData = response.data.meta || response.data.pagination;
      setQuestionPagination(
        metaData
          ? {
              page: Number(metaData.page),
              limit: Number(metaData.limit),
              total: Number(metaData.total),
              totalPages: Number(metaData.totalPages),
            }
          : {
              page: Number(page),
              limit: Number(limit),
              total: Number(totalQuestionsFallback),
              totalPages: Math.ceil(totalQuestionsFallback / limit)
            }
      );
    } catch (error) {
      toast.error(getAxiosErrorMessage(error));
    } finally {
      setQuestionsLoading(false);
    }
  };

  const toggleTest = (testId: string, totalQuestions: number) => {
    if (openTestId === testId) {
      setOpenTestId(null);
      setOpenQuestionId(null);
      setQuestions([]);
      return;
    }
    setOpenTestId(testId);
    setOpenQuestionId(null);
    setQuestions([]);
    setQuestionSearch("");
    setQuestionPagination({ ...paginationInitial, total: totalQuestions });
    getQuestions(1, paginationInitial.limit, testId, "", totalQuestions);
  };

  const toggleQuestion = (id: string) => {
    setOpenQuestionId(openQuestionId === id ? null : id);
  };

  useEffect(() => {
    if (openTestId) {
      const activeTest = tests.find((t) => t.id === openTestId);
      const fallbackCount = activeTest?.questions?.length || activeTest?._count?.testQuestions || 0;
      getQuestions(1, questionPagination.limit, openTestId, debouncedQuestionSearch, fallbackCount);
    }
  }, [debouncedQuestionSearch]);

  return (
    <div className="flex flex-col gap-4 px-4 py-6">
      <div className="flex justify-between items-center w-full">
        <div>
          <h2 className="text-2xl font-bold text-slate-800 flex items-center gap-2">
            <RotateCcw className="text-blue-600" /> Tests
          </h2>
          <p className="text-slate-500 text-sm mt-1">Manage your created tests.</p>
        </div>
      </div>

      <Card className="shadow-sm border border-slate-200 rounded-xl">
        <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-4">
          <div className="flex flex-wrap items-center gap-3 w-full sm:w-auto">
            <div className="w-full md:w-72">
              <Input
                placeholder="Search Tests..."
                prefix={<Search size={16} className="text-slate-400" />}
                allowClear
                value={search}
                onChange={(e) => setSearch(e.target.value)}
              />
            </div>

            <div className="w-full md:w-56">
              <Select
                placeholder={
                  <span className="flex items-center gap-1.5 text-slate-400">
                    Filter by Subject
                  </span>
                }
                className="w-full"
                allowClear
                loading={subjectsLoading}
                value={selectedSubjectId}
                onChange={(value) => setSelectedSubjectId(value)}
                onPopupScroll={handleSubjectPopupScroll}
                optionLabelProp="name"
                options={subjects.map((sub) => ({
                  value: sub.id,
                  name: sub.subjectName,
                  label: (
                    <div className="flex items-center gap-2">
                      {sub.isShared && (
                        <span title={`Shared by Exam Infra`}>
                          <Share2 size={12} className="text-purple-500 flex-shrink-0" />
                        </span>
                      )}
                      <span className="font-medium text-slate-700 truncate">{sub.subjectName}</span>
                    </div>
                  )
                }))}
              />
            </div>
          </div>

          <div className="text-slate-500 text-sm whitespace-nowrap self-end sm:self-center">
            Total Tests:{" "}
            <span className="font-semibold text-slate-800">
              {pagination.total}
            </span>
          </div>
        </div>

        <Spin spinning={loading}>
          {tests.length === 0 && !loading ? (
            <div className="min-h-[200px] flex items-center justify-center">
              <Empty description={debouncedSearch || selectedSubjectId ? "No tests found matching your criteria" : "No tests available"} />
            </div>
          ) : (
            <div className="space-y-3">
              {tests.map((test) => {
                const qCount = test.questions?.length || test._count?.testQuestions || 0;
                const isMapped = (test._count?.practiceTests || 0) > 0;
                return (
                  <AccordionRow
                    key={test.id}
                    className="bg-white shadow-sm border border-slate-200 rounded-xl overflow-hidden mb-3"
                    title={
                      <div className="w-full flex items-center justify-between gap-3">
                        <div className="flex items-center justify-between w-full">
                          <div className="flex items-center gap-2 flex-wrap">
                            <h2 className="text-md font-semibold text-slate-900">{test.title}</h2>
                            <p className="text-xs text-slate-500 mt-0.5 flex items-center gap-2">
                              <span>{qCount} Questions</span>
                            </p>
                            {test.referenceSourceId && (
                              <div className="flex items-center gap-1.5 px-2 py-0.5 bg-blue-50 border border-blue-100 rounded-md">
                                <Share2 size={12} className="text-blue-500" />
                                <span className="text-[11px] font-medium text-blue-600">
                                  Shared by Exam Infra
                                </span>
                              </div>
                            )}
                          </div>
                          {test.subject?.subjectName && (
                            <div className="px-2 py-0.5 text-[11px] font-medium text-slate-600 bg-slate-100 border border-slate-200/60 rounded-md select-none shrink-0">
                              {test.subject.subjectName}
                            </div>
                          )}
                        </div>
                        <div className="flex items-center gap-1 pl-2 border-l border-slate-200 ml-2" onClick={(e) => e.stopPropagation()}>
                          <Tooltip title={test.referenceSourceId ? "Cannot edit a shared test" : "Edit Test"}>
                            <div style={{ display: 'inline-block' }}>
                              <button
                                className={`p-1.5 rounded-xl transition-colors ${test.referenceSourceId ? 'text-slate-300 cursor-not-allowed' : 'text-slate-400 hover:text-blue-600 hover:bg-blue-50'}`}
                                disabled={!!test.referenceSourceId}
                                onClick={() => { if (!test.referenceSourceId) navigate(ROUTE_CONSTANTS.TestsEdit, { state: test }) }}
                              >
                                <Pencil size={15} />
                              </button>
                            </div>
                          </Tooltip>

                          <Popconfirm
                            title="This action will remove the test from all mapped Practice Tests. Continue?"
                            onConfirm={() => handleDelete(test.id)}
                            okText="Yes"
                            cancelText="No"
                            disabled={test.hasResults || !!test.referenceSourceId}
                          >
                            <Tooltip title={test.hasResults ? "Cannot delete this test because students have already taken it." : test.referenceSourceId ? "Cannot delete a shared test" : "Delete Test"}>
                              <div style={{ display: 'inline-block' }}>
                                <button
                                  className={`p-1.5 rounded-xl transition-colors ${test.hasResults || test.referenceSourceId ? 'text-slate-300 cursor-not-allowed' : 'text-slate-400 hover:text-red-600 hover:bg-red-50'}`}
                                  disabled={test.hasResults || !!test.referenceSourceId}
                                >
                                  <Trash2 size={15} />
                                </button>
                              </div>
                            </Tooltip>
                          </Popconfirm>
                        </div>
                      </div>
                    }
                    isOpen={openTestId === test.id}
                    onToggle={() => toggleTest(test.id, qCount)}
                    disabled={qCount === 0}
                    content={
                      <>
                        <div className="mt-2 flex gap-3 items-end w-[18rem]">
                          <Input
                            placeholder={"Search Questions"}
                            prefix={<Search size={16} />}
                            autoComplete="off"
                            allowClear
                            value={questionSearch}
                            onChange={(e) => setQuestionSearch(e.target.value)}
                          />
                        </div>
                        <Spin spinning={questionsLoading}>
                          {questions.length === 0 && !questionsLoading ? (
                            <div className="min-h-[100px] flex items-center justify-center">
                              <Empty description={debouncedQuestionSearch ? "No question found for your search" : "No question available"} />
                            </div>
                          ) : (
                            <>
                              {questions.map((q) => {
                                const isQuestionOpen = openQuestionId === q.id;
                                return (
                                  <AccordionRow
                                    key={q.id}
                                    hideIcon
                                    className="bg-white shadow-sm border border-slate-100 overflow-hidden my-2"
                                    title={
                                      <div className="flex items-center gap-4 p-0 cursor-pointer transition-colors duration-200">
                                        <div className="text-slate-400 transition-transform duration-200">
                                          {isQuestionOpen ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
                                        </div>
                                        <div className="flex-1 grid grid-cols-1 xl:grid-cols-12 gap-4 items-center">
                                          <div className="xl:col-span-4 flex items-center gap-3">
                                            <div className="hidden sm:flex items-center justify-center p-1 rounded bg-slate-100 text-brand-blue shrink-0">
                                              <ClipboardList size={20} />
                                            </div>
                                            <h3 className={`text-sm font-medium text-left leading-relaxed line-clamp-1 ${isQuestionOpen ? "text-brand-blue" : "text-slate-700"}`}>
                                              {q.questionText}
                                            </h3>
                                          </div>
                                          <div className="xl:col-span-8 flex flex-wrap xl:justify-end items-center gap-x-3 gap-y-2 mt-2 xl:mt-0">
                                            {q.subject && (
                                              <span className="text-[11px] px-2 py-0.5 rounded bg-purple-50 text-purple-600 border border-purple-100">
                                                {typeof q.subject === "object" ? (q.subject as any).subjectName : q.subject}
                                              </span>
                                            )}
                                            {q.topic && <span className="text-[11px] px-2 py-0.5 rounded bg-blue-50 text-blue-600 border border-blue-100">{q.topic}</span>}
                                            {q.language && <span className="text-[11px] px-2 py-0.5 rounded bg-amber-50 text-amber-600 border border-amber-100">{q.language}</span>}
                                            {q.updatedAt && (
                                              <div className="hidden 2xl:flex items-center gap-1.5 text-[11px] text-slate-400 min-w-[80px] justify-end">
                                                <Clock size={12} />
                                                <span>{dayjs(q.updatedAt).format("DD-MM-YYYY")}</span>
                                              </div>
                                            )}
                                            <span className={`text-[10px] px-2.5 py-0.5 rounded-full font-semibold border min-w-[60px] text-center ${difficultyColor(q.difficulty === "Easy" ? Difficulty.Easy : q.difficulty === "Medium" ? Difficulty.Medium : Difficulty.Hard)}`}>
                                              {q.difficulty}
                                            </span>
                                          </div>
                                        </div>
                                      </div>
                                    }
                                    isOpen={isQuestionOpen}
                                    onToggle={() => toggleQuestion(q.id)}
                                    content={
                                      <div className="pt-2 pb-6 px-4 sm:px-8 bg-slate-50 border-t border-slate-100">
                                        <div className="mb-4 flex flex-col items-start gap-2">
                                          <div className="text-sm font-medium text-left leading-relaxed text-slate-700 text-wrap">{q.questionText}</div>
                                          {q.questionImage && <img src={q.questionImage} alt="Question" className="h-[5rem] object-contain rounded-md mt-2" />}
                                        </div>
                                        <div className="space-y-3">
                                          {q.options?.map((option: any, idx: number) => {
                                            const isCorrect = idx === q.correctAnswer;
                                            let optionClass = "w-full text-left p-3 rounded-xl border text-sm font-medium flex justify-between items-center transition-all duration-200 cursor-default ";
                                            if (isCorrect) optionClass += "bg-green-50 border-green-500 text-green-800 shadow-sm ring-1 ring-green-500/20";
                                            else optionClass += "bg-white border-slate-200 text-slate-500 opacity-80";
                                            return (
                                              <div key={idx} className={optionClass}>
                                                <div className="flex items-center gap-3">
                                                  <span className={`flex items-center justify-center w-6 h-6 rounded-full text-xs font-bold border ${isCorrect ? "border-green-600 bg-green-100 text-green-700" : "border-slate-300 bg-slate-50 text-slate-500"}`}>
                                                    {String.fromCharCode(65 + idx)}
                                                  </span>
                                                  {option.option !== "" && <span>{option.option}</span>}
                                                  {option.optionImage && <img src={option.optionImage} alt="Option" className="h-[5rem] w-auto object-contain rounded-xl ml-5" />}
                                                </div>
                                                {isCorrect && <CheckCircle className="text-green-600" size={18} />}
                                              </div>
                                            );
                                          })}
                                        </div>
                                        {(q.explanation || q.explanationImage) && (
                                          <div className="mt-6 space-y-4">
                                            <div className="p-4 rounded-xl border bg-blue-50 border-blue-100">
                                              <h4 className="text-xs font-bold uppercase tracking-wider mb-2 flex items-center gap-2 text-blue-700">
                                                <Info size={14} /> Explanation
                                              </h4>
                                              {q.explanation && <p className="text-sm text-slate-700 leading-relaxed font-medium whitespace-pre-line">{q.explanation}</p>}
                                              {q.explanationImage && <img src={q.explanationImage} alt="Explanation" className="h-[5rem] w-auto object-contain rounded-xl mt-3" />}
                                            </div>
                                          </div>
                                        )}
                                      </div>
                                    }
                                  />
                                );
                              })}

                              <div className="flex justify-end pb-2 pt-2">
                                <Pagination
                                  current={Number(questionPagination.page) || 1}
                                  total={Number(questionPagination.total) || 0}
                                  pageSize={Number(questionPagination.limit) || 10}
                                  pageSizeOptions={["10", "20", "50", "100"]}
                                  onChange={(p, pageSize) => {
                                    const currentLimit = pageSize || 10;
                                    setQuestionPagination({
                                      ...questionPagination,
                                      page: p,
                                      limit: currentLimit
                                    });
                                    getQuestions(p, currentLimit, openTestId!, questionSearch, qCount);
                                  }}
                                  showSizeChanger
                                />
                              </div>
                            </>
                          )}
                        </Spin>
                      </>
                    }
                  />
                );
              })}

              <div className="flex justify-end pt-4">
                <Pagination
                  current={Number(pagination.page) || 1}
                  total={Number(pagination.total) || 0}
                  pageSize={Number(pagination.limit) || 10}
                  pageSizeOptions={["10", "20", "50", "100"]}
                  onChange={(page, pageSize) => {
                    const currentLimit = pageSize || 10;
                    fetchTests(page, currentLimit, selectedSubjectId);
                  }}
                  showSizeChanger
                />
              </div>
            </div>
          )}
        </Spin>
      </Card>
    </div>
  );
};

export default TestTree;