import { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router";
import { ProtectedRoute } from "~/components/ProtectedRoute";
import { StatCard } from "~/components/StatCard";
import { SubjectCard } from "~/components/SubjectCard";
import { LoadingSpinner } from "~/components/LoadingSpinner";
import { Button } from "~/components/Button";
import { api } from "~/api/client";
import type { Subject, Grade, ReportPeriod, User, TeacherGrade } from "~/types/api";
import { calculateReportCard, calculateOverallGPA, calculateTargetProgress, getTargetStatusColor } from "~/utils/gradeCalculations";
import { formatGradeBySystem, germanGradeToPercentage, type GradeSystem } from "~/utils/gradeSystems";

export default function Dashboard() {
  const navigate = useNavigate();
  const [user, setUser] = useState<User | null>(null);
  const [subjects, setSubjects] = useState<Subject[]>([]);
  const [grades, setGrades] = useState<Grade[]>([]);
  const [periods, setPeriods] = useState<ReportPeriod[]>([]);
  const [selectedPeriod, setSelectedPeriod] = useState<ReportPeriod | null>(null);
  const [teacherGrades, setTeacherGrades] = useState<TeacherGrade[]>([]);
  const [editingTeacherGrade, setEditingTeacherGrade] = useState<{ subjectId: string; value: string; maxValue: string; notes: string } | null>(null);
  const [loading, setLoading] = useState(true);
  const [exporting, setExporting] = useState(false);
  const [deletingTeacherGradeId, setDeletingTeacherGradeId] = useState<string | null>(null);

  useEffect(() => {
    loadData();
  }, []);

  const loadData = async () => {
    try {
      const [userData, subjectsData, gradesData, periodsData, teacherGradesData] = await Promise.all([
        api.getMe(),
        api.getSubjects(),
        api.getGrades(),
        api.getPeriods(),
        api.getTeacherGrades(),
      ]);

      setUser(userData);
      setSubjects(subjectsData);
      setGrades(gradesData);
      setPeriods(periodsData);
      setTeacherGrades(teacherGradesData);

      if (periodsData.length > 0) {
        // Find the period that contains today's date
        const today = new Date();
        const currentPeriod = periodsData.find(period => {
          const start = new Date(period.start_date);
          const end = new Date(period.end_date);
          return today >= start && today <= end;
        });
        
        // Use current period if found, otherwise use the most recent period (first in list)
        setSelectedPeriod(currentPeriod || periodsData[0]);
      }
    } catch (error) {
      console.error("Failed to load data:", error);
    } finally {
      setLoading(false);
    }
  };

  const handleLogout = () => {
    api.logout();
    navigate("/login");
  };

  const handleTeacherGradeClick = (subjectId: string) => {
    const subject = subjects.find(s => s._id === subjectId);
    if (!subject || !selectedPeriod) return;

    const existing = teacherGrades.find(
      tg => tg.subject_id === subjectId && tg.period_id === selectedPeriod._id
    );

    const config = getGradeInputConfig(subject.grade_system as GradeSystem);
    
    setEditingTeacherGrade({
      subjectId,
      value: existing ? existing.grade.toString() : "",
      maxValue: existing ? existing.max_grade.toString() : config.maxGradeValue,
      notes: existing?.notes || "",
    });
  };

  const handleSaveTeacherGrade = async () => {
    if (!editingTeacherGrade || !selectedPeriod) return;

    try {
      const subject = subjects.find(s => s._id === editingTeacherGrade.subjectId);
      if (!subject) return;

      const config = getGradeInputConfig(subject.grade_system as GradeSystem);
      const finalMaxGrade = config.showMaxGradeInput 
        ? parseFloat(editingTeacherGrade.maxValue) 
        : parseFloat(config.maxGradeValue);

      const data = {
        subject_id: editingTeacherGrade.subjectId,
        period_id: selectedPeriod._id,
        grade: parseFloat(editingTeacherGrade.value),
        max_grade: finalMaxGrade,
        notes: editingTeacherGrade.notes || undefined,
      };

      const result = await api.createTeacherGrade(data);
      setTeacherGrades([...teacherGrades.filter(
        tg => !(tg.subject_id === result.subject_id && tg.period_id === result.period_id)
      ), result]);
      setEditingTeacherGrade(null);
    } catch (error) {
      alert("Failed to save teacher grade");
    }
  };

  const handleDeleteTeacherGrade = async (subjectId: string) => {
    if (!selectedPeriod) return;

    const existing = teacherGrades.find(
      tg => tg.subject_id === subjectId && tg.period_id === selectedPeriod._id
    );

    if (existing && confirm("Remove teacher's grade?")) {
      try {
        setDeletingTeacherGradeId(subjectId);
        await api.deleteTeacherGrade(existing._id);
        setTeacherGrades(teacherGrades.filter(tg => tg._id !== existing._id));
      } catch (error) {
        alert("Failed to delete teacher grade");
      } finally {
        setDeletingTeacherGradeId(null);
      }
    }
  };

  const getGradeInputConfig = (gradeSystem: GradeSystem) => {
    switch (gradeSystem) {
      case "german":
        return {
          label: "German Grade",
          placeholder: "1.0",
          min: "1",
          max: "6",
          step: "0.1",
          maxGradeValue: "6",
          showMaxGradeInput: false,
        };
      case "us-letter":
        return {
          label: "Percentage",
          placeholder: "85",
          min: "0",
          max: "100",
          step: "0.01",
          maxGradeValue: "100",
          showMaxGradeInput: false,
        };
      default:
        return {
          label: "Grade",
          placeholder: "85",
          min: "0",
          max: undefined,
          step: "0.01",
          maxGradeValue: "100",
          showMaxGradeInput: true,
        };
    }
  };

  const handleExportCSV = async () => {
    try {
      setExporting(true);
      await api.exportGradesCSV(selectedPeriod?._id);
    } catch (error) {
      console.error("Failed to export grades:", error);
      alert("Failed to export grades. Please try again.");
    } finally {
      setExporting(false);
    }
  };

  if (loading) {
    return (
      <ProtectedRoute>
        <div className="min-h-screen flex items-center justify-center">
          <LoadingSpinner size="lg" />
        </div>
      </ProtectedRoute>
    );
  }

  const reportCardData = selectedPeriod
    ? calculateReportCard(
        subjects,
        grades,
        new Date(selectedPeriod.start_date),
        new Date(selectedPeriod.end_date)
      )
    : [];

  const calculatedGPA = calculateOverallGPA(reportCardData);
  
  // Calculate GPA with teacher grade overrides
  const getSubjectFinalGrade = (subjectId: string, calculatedAverage: number) => {
    if (!selectedPeriod) return calculatedAverage;
    const teacherGrade = teacherGrades.find(
      tg => tg.subject_id === subjectId && tg.period_id === selectedPeriod._id
    );
    if (!teacherGrade) return calculatedAverage;
    
    const subject = subjects.find(s => s._id === subjectId);
    if (!subject) return calculatedAverage;
    
    // Convert teacher grade to percentage
    const gradeSystem = subject.grade_system as GradeSystem || "percentage";
    if (gradeSystem === "german" && teacherGrade.max_grade === 6) {
      return germanGradeToPercentage(teacherGrade.grade);
    }
    return (teacherGrade.grade / teacherGrade.max_grade) * 100;
  };
  
  const overallGPA = selectedPeriod && reportCardData.length > 0
    ? reportCardData.reduce((sum, data) => {
        const finalGrade = getSubjectFinalGrade(data.subject._id, data.overallAverage);
        return sum + finalGrade;
      }, 0) / reportCardData.length
    : calculatedGPA;
  
  // Use the first subject's grading system as the primary system
  const primaryGradeSystem = (subjects[0]?.grade_system as GradeSystem) || "percentage";

  return (
    <ProtectedRoute>
      <div className="min-h-screen bg-gray-50">
        {/* Header */}
        <header className="bg-white shadow-sm border-b">
          <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
            <div className="flex justify-between items-center">
              <div>
                <h1 className="text-2xl font-bold text-gray-900">Grademaxxing</h1>
                <p className="text-sm text-gray-600">Welcome back, {user?.username}!</p>
              </div>
              <div className="flex gap-3">
                <Link to="/periods">
                  <Button variant="ghost">Report Periods</Button>
                </Link>
                <Link to="/subjects">
                  <Button variant="secondary">Manage Subjects</Button>
                </Link>
                <Button variant="ghost" onClick={handleLogout}>
                  Logout
                </Button>
              </div>
            </div>
          </div>
        </header>

        <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
          {/* Period Selector */}
          {periods.length > 0 && (
            <div className="mb-8 flex items-end gap-4">
              <div className="flex-1">
                <label className="block text-sm font-medium text-gray-700 mb-2">
                  Select Report Period
                </label>
                <select
                  value={selectedPeriod?._id || ""}
                  onChange={(e) => {
                    const period = periods.find((p) => p._id === e.target.value);
                    setSelectedPeriod(period || null);
                  }}
                  className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
                >
                  {periods.map((period) => (
                    <option key={period._id} value={period._id}>
                      {period.name} ({new Date(period.start_date).toLocaleDateString()} -{" "}
                      {new Date(period.end_date).toLocaleDateString()})
                    </option>
                  ))}
                </select>
              </div>
              <Button
                onClick={handleExportCSV}
                disabled={exporting}
                variant="secondary"
              >
                {exporting ? "Exporting..." : "📥 Export CSV"}
              </Button>
            </div>
          )}

          {/* Stats Overview */}
          <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
            <StatCard
              title="Overall Average"
              value={
                overallGPA > 0
                  ? selectedPeriod && teacherGrades.some(tg => tg.period_id === selectedPeriod._id) && calculatedGPA !== overallGPA
                    ? `${formatGradeBySystem(overallGPA, primaryGradeSystem, 1)} (${formatGradeBySystem(calculatedGPA, primaryGradeSystem, 1)})`
                    : formatGradeBySystem(overallGPA, primaryGradeSystem, 1)
                  : "-"
              }
              subtitle={selectedPeriod?.name || "All time"}
              color="#3b82f6"
            />
            <StatCard
              title="Total Subjects"
              value={subjects.length}
              subtitle={`${reportCardData.filter((d) => d.grades.length > 0).length} with grades`}
              color="#10b981"
            />
            <StatCard
              title="Total Grades"
              value={grades.length}
              subtitle={`${
                selectedPeriod
                  ? reportCardData.reduce((sum, d) => sum + d.grades.length, 0)
                  : grades.length
              } in period`}
              color="#f59e0b"
            />
          </div>

          {/* Improvement Tips */}
          {selectedPeriod && reportCardData.length > 0 && (
            (() => {
              const tipsForSubjects = reportCardData
                .filter(data => data.categoryAverages.length > 1 && data.categoryAverages.every(c => c.average > 0))
                .map(data => {
                  const sortedCategories = [...data.categoryAverages].sort((a, b) => a.average - b.average);
                  const weakest = sortedCategories[0];
                  const strongest = sortedCategories[sortedCategories.length - 1];
                  const difference = strongest.average - weakest.average;
                  
                  if (difference > 5) {
                    return {
                      subject: data.subject,
                      weakest,
                      strongest,
                      difference
                    };
                  }
                  return null;
                })
                .filter(tip => tip !== null);

              if (tipsForSubjects.length > 0) {
                return (
                  <div className="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6">
                    <div className="flex">
                      <div className="flex-shrink-0">
                        <svg className="h-5 w-5 text-blue-500" viewBox="0 0 20 20" fill="currentColor">
                          <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
                        </svg>
                      </div>
                      <div className="ml-3">
                        <h3 className="text-sm font-medium text-blue-800">💡 Improvement Tips</h3>
                        <div className="mt-2 text-sm text-blue-700 space-y-2">
                          {tipsForSubjects.map((tip, idx) => (
                            <p key={idx}>
                              <strong>{tip!.subject.name}:</strong> Your {tip!.weakest.categoryName} ({formatGradeBySystem(
                                tip!.weakest.average,
                                primaryGradeSystem,
                                1
                              )}) needs work compared to {tip!.strongest.categoryName} ({formatGradeBySystem(
                                tip!.strongest.average,
                                primaryGradeSystem,
                                1
                              )}). Focus on {tip!.weakest.categoryName.toLowerCase()} to improve!
                            </p>
                          ))}
                        </div>
                      </div>
                    </div>
                  </div>
                );
              }
              return null;
            })()
          )}

          {/* Report Card */}
          {selectedPeriod && reportCardData.length > 0 ? (
            <div className="bg-white rounded-lg shadow p-6 mb-8">
              <h2 className="text-xl font-bold text-gray-900 mb-4">
                Report Card - {selectedPeriod.name}
              </h2>
              <div className="overflow-x-auto">
                <table className="w-full">
                  <thead>
                    <tr className="border-b">
                      <th className="text-left py-3 px-4 font-semibold text-gray-700">
                        Subject
                      </th>
                      {reportCardData[0]?.categoryAverages.map((cat) => (
                        <th
                          key={cat.categoryName}
                          className="text-right py-3 px-4 font-semibold text-gray-700"
                        >
                          {cat.categoryName} ({cat.weight}%)
                        </th>
                      ))}
                      <th className="text-right py-3 px-4 font-semibold text-gray-700">
                        Final Grade
                      </th>
                      <th className="text-right py-3 px-4 font-semibold text-gray-700">
                        Target
                      </th>
                      <th className="text-right py-3 px-4 font-semibold text-gray-700">
                        Diff
                      </th>
                      <th className="text-right py-3 px-4 font-semibold text-gray-700">
                        Teacher's Grade
                      </th>
                    </tr>
                  </thead>
                  <tbody>
                    {reportCardData.map((data) => {
                      const teacherGrade = selectedPeriod ? teacherGrades.find(
                        tg => tg.subject_id === data.subject._id && tg.period_id === selectedPeriod._id
                      ) : null;
                      
                      const isEditing = editingTeacherGrade?.subjectId === data.subject._id;
                      
                      // Calculate target progress for this subject
                      const targetProgress = calculateTargetProgress(data.overallAverage, data.subject);
                      
                      return (
                      <tr key={data.subject._id} className="border-b hover:bg-gray-50">
                        <td className="py-3 px-4 font-medium">{data.subject.name}</td>
                        {data.categoryAverages.map((cat) => (
                          <td key={cat.categoryName} className="text-right py-3 px-4">
                            {cat.average > 0
                              ? formatGradeBySystem(
                                  cat.average,
                                  primaryGradeSystem,
                                  1
                                )
                              : "-"}
                          </td>
                        ))}
                        <td className="text-right py-3 px-4 font-bold">
                          {teacherGrade ? (
                            <span className="text-green-700">
                              {formatGradeBySystem(
                                primaryGradeSystem === "german" && teacherGrade.max_grade === 6
                                  ? germanGradeToPercentage(teacherGrade.grade)
                                  : (teacherGrade.grade / teacherGrade.max_grade) * 100,
                                primaryGradeSystem,
                                1
                              )}
                              {data.overallAverage > 0 && (
                                <span className="text-gray-500 text-sm font-normal">
                                  {" "}({formatGradeBySystem(
                                    data.overallAverage,
                                    primaryGradeSystem,
                                    1
                                  )})
                                </span>
                              )}
                            </span>
                          ) : (
                            <span className="text-blue-600">
                              {data.overallAverage > 0
                                ? formatGradeBySystem(
                                    data.overallAverage,
                                    primaryGradeSystem,
                                    1
                                  )
                                : "-"}
                            </span>
                          )}
                        </td>
                        <td className="text-right py-3 px-4 text-gray-600">
                          {targetProgress.status !== "no-target"
                            ? primaryGradeSystem === "german" && data.subject.target_grade_max === 6
                              ? data.subject.target_grade?.toFixed(1)
                              : formatGradeBySystem(
                                  targetProgress.targetPercentage,
                                  primaryGradeSystem,
                                  1
                                )
                            : "-"}
                        </td>
                        <td className={`text-right py-3 px-4 font-semibold ${getTargetStatusColor(targetProgress.status)}`}>
                          {targetProgress.status !== "no-target" && data.overallAverage > 0
                            ? (targetProgress.difference > 0 ? "+" : "") + targetProgress.difference.toFixed(1) + "%"
                            : "-"}
                        </td>
                        <td className="text-right py-3 px-4">
                          {isEditing ? (
                            <div className="flex items-center gap-2 justify-end">
                              <input
                                type="number"
                                value={editingTeacherGrade.value}
                                onChange={(e) => setEditingTeacherGrade({
                                  ...editingTeacherGrade,
                                  value: e.target.value
                                })}
                                className="w-20 px-2 py-1 border rounded text-sm"
                                placeholder={getGradeInputConfig(primaryGradeSystem).placeholder}
                                min={getGradeInputConfig(primaryGradeSystem).min}
                                max={getGradeInputConfig(primaryGradeSystem).max}
                                step={getGradeInputConfig(primaryGradeSystem).step}
                              />
                              <button
                                onClick={handleSaveTeacherGrade}
                                className="text-green-600 hover:text-green-800"
                                title="Save"
                              >
                                ✓
                              </button>
                              <button
                                onClick={() => setEditingTeacherGrade(null)}
                                className="text-red-600 hover:text-red-800"
                                title="Cancel"
                              >
                                ✗
                              </button>
                            </div>
                          ) : teacherGrade ? (
                            <div className="flex items-center gap-2 justify-end">
                              <span className="font-bold text-green-700">
                                {formatGradeBySystem(
                                  primaryGradeSystem === "german" && teacherGrade.max_grade === 6
                                    ? germanGradeToPercentage(teacherGrade.grade)
                                    : (teacherGrade.grade / teacherGrade.max_grade) * 100,
                                  primaryGradeSystem,
                                  1
                                )}
                              </span>
                              <button
                                onClick={() => handleTeacherGradeClick(data.subject._id)}
                                className="text-blue-600 hover:text-blue-800"
                                title="Edit"
                              >
                                ✎
                              </button>
                              <button
                                onClick={() => handleDeleteTeacherGrade(data.subject._id)}
                                className="text-red-600 hover:text-red-800 disabled:opacity-50"
                                title="Remove"
                                disabled={deletingTeacherGradeId === data.subject._id}
                              >
                                {deletingTeacherGradeId === data.subject._id ? "..." : "✗"}
                              </button>
                            </div>
                          ) : (
                            <button
                              onClick={() => handleTeacherGradeClick(data.subject._id)}
                              className="text-blue-600 hover:text-blue-800 text-sm"
                            >
                              + Add
                            </button>
                          )}
                        </td>
                      </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>
          ) : (
            <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-6 mb-8">
              <p className="text-yellow-800">
                {periods.length === 0 ? (
                  <>
                    No report periods defined.{" "}
                    <Link to="/periods" className="underline font-medium">
                      Create your first period
                    </Link>
                  </>
                ) : (
                  "No grades recorded for this period yet."
                )}
              </p>
            </div>
          )}

          {/* Subjects Grid */}
          <div className="mb-6 flex justify-between items-center">
            <h2 className="text-xl font-bold text-gray-900">Your Subjects</h2>
            <Link to="/subjects/new">
              <Button>+ Add Subject</Button>
            </Link>
          </div>

          {subjects.length > 0 ? (
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
              {subjects.map((subject) => {
                const subjectGrades = grades.filter((g) => g.subject_id === subject._id);
                const avgData = reportCardData.find((d) => d.subject._id === subject._id);
                const teacherGrade = selectedPeriod ? teacherGrades.find(
                  tg => tg.subject_id === subject._id && tg.period_id === selectedPeriod._id
                ) : null;
                
                const calculatedAverage = avgData?.overallAverage;
                const finalAverage = calculatedAverage !== undefined
                  ? getSubjectFinalGrade(subject._id, calculatedAverage)
                  : undefined;
                
                return (
                  <SubjectCard
                    key={subject._id}
                    subject={subject}
                    averageGrade={finalAverage}
                    calculatedAverage={calculatedAverage}
                    gradeSystem={primaryGradeSystem}
                  />
                );
              })}
            </div>
          ) : (
            <div className="bg-white rounded-lg shadow p-12 text-center">
              <p className="text-gray-600 mb-4">No subjects yet. Create your first subject!</p>
              <Link to="/subjects/new">
                <Button>+ Add Subject</Button>
              </Link>
            </div>
          )}
        </main>
      </div>
    </ProtectedRoute>
  );
}
