import { useEffect, useMemo, useState } from "react";
import { BarChart3, Table2 } from "lucide-react";
import { toast } from "sonner";

import { getClients } from "../api/clients";
import { getProjects, type Project } from "../api/projects";
import {
  createReportExport,
  getChartReport,
  getDayDetailsReport,
  getTableReport,
  type ChartReportResponse,
  type DayDetailsResponse,
  type ReportFilters,
  type TableReportResponse,
} from "../api/reports";
import { getTags, type Tag } from "../api/tags";
import { fetchWorkspaceMemberships, type WorkspaceMembership } from "../api/workspaces";
import { ReportsChartPanel } from "../components/reports/ReportsChartPanel";
import { ReportsFilterBar, type ReportsFilterDraft } from "../components/reports/ReportsFilterBar";
import { ReportsTablePanel } from "../components/reports/ReportsTablePanel";
import { useWorkspace } from "../context/WorkspaceContext";
import { useTranslation } from "../hooks/useTranslation";
import { canWorkspace, WORKSPACE_MEMBERS_VIEW } from "../lib/permissions";

type Tab = "chart" | "table";

const normalizeDigits = (value: string) =>
  value
    .replace(/[۰-۹]/g, (digit) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(digit)))
    .replace(/[٠-٩]/g, (digit) => String("٠١٢٣٤٥٦٧٨٩".indexOf(digit)));

const getPersianDateParts = (value: Date) => {
  const parts = new Intl.DateTimeFormat("fa-IR-u-ca-persian", {
    year: "numeric",
    month: "numeric",
    day: "numeric",
  }).formatToParts(value);

  const year = Number(normalizeDigits(parts.find((part) => part.type === "year")?.value || ""));
  const month = Number(normalizeDigits(parts.find((part) => part.type === "month")?.value || ""));
  const day = Number(normalizeDigits(parts.find((part) => part.type === "day")?.value || ""));

  return { year, month, day };
};

const getCurrentLanguageAwareMonthRange = (lang: "en" | "fa") => {
  const today = new Date();

  if (lang !== "fa") {
    const start = new Date(today.getFullYear(), today.getMonth(), 1);
    const end = new Date(today.getFullYear(), today.getMonth() + 1, 0);
    return {
      from_date: start.toISOString().slice(0, 10),
      to_date: end.toISOString().slice(0, 10),
    };
  }

  const todayParts = getPersianDateParts(today);
  const start = new Date(today);
  while (true) {
    const parts = getPersianDateParts(start);
    if (parts.year === todayParts.year && parts.month === todayParts.month && parts.day === 1) {
      break;
    }
    start.setDate(start.getDate() - 1);
  }

  const end = new Date(today);
  while (true) {
    const next = new Date(end);
    next.setDate(next.getDate() + 1);
    const parts = getPersianDateParts(next);
    if (parts.year !== todayParts.year || parts.month !== todayParts.month) {
      break;
    }
    end.setDate(end.getDate() + 1);
  }

  return {
    from_date: start.toISOString().slice(0, 10),
    to_date: end.toISOString().slice(0, 10),
  };
};

export default function Reports() {
  const { t, lang } = useTranslation();
  const { activeWorkspace } = useWorkspace();
  const [tab, setTab] = useState<Tab>("chart");
  const [projects, setProjects] = useState<Project[]>([]);
  const [clients, setClients] = useState<{ id: string; name: string }[]>([]);
  const [tags, setTags] = useState<Tag[]>([]);
  const [memberships, setMemberships] = useState<WorkspaceMembership[]>([]);
  const [chartData, setChartData] = useState<ChartReportResponse | null>(null);
  const [tableData, setTableData] = useState<TableReportResponse | null>(null);
  const [dayDetails, setDayDetails] = useState<DayDetailsResponse | null>(null);
  const [openDay, setOpenDay] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [isLoadingUsers, setIsLoadingUsers] = useState(false);
  const [exportState, setExportState] = useState({
    excel: { pending: false, cooldownSeconds: 0 },
    pdf: { pending: false, cooldownSeconds: 0 },
  });

  const canSelectUsers = canWorkspace(activeWorkspace?.my_role, WORKSPACE_MEMBERS_VIEW);
  const isWorkspaceRoleResolved = Boolean(activeWorkspace?.my_role);
  const showUserFilterLoading = !isWorkspaceRoleResolved || (canSelectUsers && isLoadingUsers);

  const [filters, setFilters] = useState<ReportsFilterDraft>({
    period: "this_month",
    from_date: "",
    to_date: "",
    user: "",
    client: "",
    project: "",
    tags: [],
  });

  useEffect(() => {
    if (!activeWorkspace?.id) return;
    const loadOptions = async () => {
      try {
        const [projectsResponse, clientsResponse, tagsResponse] = await Promise.all([
          getProjects(activeWorkspace.id, { limit: 300, offset: 0 }),
          getClients(activeWorkspace.id, "", "", 300, 0),
          getTags(activeWorkspace.id, { limit: 300, offset: 0 }),
        ]);
        setProjects(projectsResponse.results || []);
        setClients((clientsResponse.results || []).map((client: { id: string; name: string }) => ({ id: client.id, name: client.name })));
        setTags(tagsResponse.results || []);
      } catch {
        toast.error(t.reports?.loadFiltersError || "Failed to load report filters.");
      }
    };
    void loadOptions();
  }, [activeWorkspace?.id, t.reports?.loadFiltersError]);

  useEffect(() => {
    if (!activeWorkspace?.id || !isWorkspaceRoleResolved) return;

    if (!canSelectUsers) {
      setMemberships([]);
      setIsLoadingUsers(false);
      return;
    }

    const loadUsers = async () => {
      setIsLoadingUsers(true);
      try {
        const membersResponse = await fetchWorkspaceMemberships({ workspace: activeWorkspace.id });
        setMemberships(membersResponse.results || []);
      } catch {
        toast.error(t.reports?.loadFiltersError || "Failed to load report filters.");
        setMemberships([]);
      } finally {
        setIsLoadingUsers(false);
      }
    };

    void loadUsers();
  }, [activeWorkspace?.id, canSelectUsers, isWorkspaceRoleResolved, t.reports?.loadFiltersError]);

  const buildApiFilters = (draft: ReportsFilterDraft): ReportFilters | null => {
    if (!activeWorkspace?.id) return null;

    return {
      workspace: activeWorkspace.id,
      period: draft.period,
      from_date: draft.from_date || undefined,
      to_date: draft.to_date || undefined,
      user: canSelectUsers ? draft.user || undefined : undefined,
      client: draft.client || undefined,
      project: draft.project || undefined,
      tags: draft.tags,
      language: lang,
    };
  };

  const apiFilters = useMemo<ReportFilters | null>(() => buildApiFilters(filters), [activeWorkspace?.id, canSelectUsers, filters, lang]);

  const runReportLoad = async (nextFilters: ReportFilters) => {
    setIsLoading(true);
    try {
      const [nextChart, nextTable] = await Promise.all([
        getChartReport(nextFilters),
        getTableReport(nextFilters),
      ]);
      setChartData(nextChart);
      setTableData(nextTable);
      setOpenDay(null);
      setDayDetails(null);
    } catch {
      toast.error(t.reports?.loadError || "Failed to load reports.");
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    if (!apiFilters) return;
    void runReportLoad(apiFilters);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [apiFilters?.workspace]);

  const handleToggleDay = async (day: string) => {
    if (!apiFilters) return;
    if (openDay === day) {
      setOpenDay(null);
      setDayDetails(null);
      return;
    }
    setOpenDay(day);
    try {
      const details = await getDayDetailsReport(apiFilters, day);
      setDayDetails(details);
    } catch {
      toast.error(t.reports?.loadDayDetailsError || "Failed to load day details.");
    }
  };

  useEffect(() => {
    const interval = window.setInterval(() => {
      setExportState((current) => ({
        excel: {
          pending: current.excel.pending,
          cooldownSeconds: Math.max(current.excel.cooldownSeconds - 1, 0),
        },
        pdf: {
          pending: current.pdf.pending,
          cooldownSeconds: Math.max(current.pdf.cooldownSeconds - 1, 0),
        },
      }));
    }, 1000);

    return () => window.clearInterval(interval);
  }, []);

  const handleExport = async (type: "excel" | "pdf") => {
    if (!apiFilters) return;
    if (exportState[type].pending || exportState[type].cooldownSeconds > 0) return;

    setExportState((current) => ({
      ...current,
      [type]: { pending: true, cooldownSeconds: 0 },
    }));

    try {
      await createReportExport(apiFilters, type, lang);
      setExportState((current) => ({
        ...current,
        [type]: { pending: false, cooldownSeconds: 60 },
      }));
      toast.success(t.reports?.exportQueued || "Export queued. You will receive a notification with the download link.");
    } catch {
      setExportState((current) => ({
        ...current,
        [type]: { pending: false, cooldownSeconds: 0 },
      }));
      toast.error(t.reports?.exportError || "Failed to queue report export.");
    }
  };

  if (!activeWorkspace) {
    return (
      <div className="p-6">
        <div className="rounded-2xl border border-slate-200 bg-white p-6 text-slate-600 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300">
          {t.reports?.selectWorkspace || "Please select a workspace first."}
        </div>
      </div>
    );
  }

  return (
    <div className="mx-auto max-w-7xl space-y-5 p-4 md:p-6">
      <div className="rounded-3xl border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-6">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
          <div>
            <h1 className="text-2xl font-bold text-slate-900 dark:text-white">{t.reports?.title || "Reports"}</h1>
            <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
              {t.reports?.description?.(activeWorkspace.name) || `Review activity reports for ${activeWorkspace.name}`}
            </p>
          </div>
          <div className="grid w-full grid-cols-2 rounded-2xl border border-slate-200 bg-slate-50 p-1 dark:border-slate-800 dark:bg-slate-950 lg:w-auto">
            <button
              type="button"
              onClick={() => setTab("chart")}
              className={`inline-flex h-11 items-center justify-center gap-2 rounded-xl px-4 text-sm font-medium transition ${
                tab === "chart"
                  ? "bg-white text-slate-900 shadow-sm dark:bg-slate-900 dark:text-white"
                  : "text-slate-500 dark:text-slate-400"
              }`}
            >
              <BarChart3 className="h-4 w-4" />
              {t.reports?.chartTab || "Chart"}
            </button>
            <button
              type="button"
              onClick={() => setTab("table")}
              className={`inline-flex h-11 items-center justify-center gap-2 rounded-xl px-4 text-sm font-medium transition ${
                tab === "table"
                  ? "bg-white text-slate-900 shadow-sm dark:bg-slate-900 dark:text-white"
                  : "text-slate-500 dark:text-slate-400"
              }`}
            >
              <Table2 className="h-4 w-4" />
              {t.reports?.tableTab || "Table"}
            </button>
          </div>
        </div>
      </div>

      <ReportsFilterBar
        value={filters}
        onApply={(draft) => {
          setFilters(draft);
          const nextFilters = buildApiFilters(draft);
          if (!nextFilters) return;
          void runReportLoad(nextFilters);
        }}
        projects={projects}
        clients={clients}
        tags={tags}
        users={memberships}
        canSelectUsers={canSelectUsers}
        isLoadingUsers={showUserFilterLoading}
        labels={{
          period: t.reports?.period || "Period",
          thisWeek: t.reports?.periodThisWeek || "This week",
          thisMonth: t.reports?.periodThisMonth || "This month",
          thisYear: t.reports?.periodThisYear || "This year",
          firstHalf: t.reports?.periodFirstHalf || "First half of year",
          secondHalf: t.reports?.periodSecondHalf || "Second half of year",
          customPeriod: t.reports?.periodCustom || "Custom period",
          fromDate: t.reports?.fromDate || "From date",
          toDate: t.reports?.toDate || "To date",
          user: t.reports?.user || "User",
          allUsers: t.reports?.allUsers || "All users",
          searchUsers: t.reports?.searchUsers || "Search users...",
          client: t.reports?.client || "Client",
          allClients: t.reports?.allClients || "All clients",
          searchClients: t.reports?.searchClients || "Search clients...",
          project: t.reports?.project || "Project",
          allProjects: t.reports?.allProjects || "All projects",
          searchProjects: t.reports?.searchProjects || "Search projects...",
          tags: t.reports?.tags || "Tags",
          allTags: t.reports?.allTags || "All tags",
          searchTags: t.reports?.searchTags || "Search tags...",
          clear: t.reports?.clear || "Clear",
          apply: t.reports?.apply || "Apply",
        }}
      />

      {isLoading ? (
        <div className="rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-600 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300">
          {t.loading || "Loading..."}
        </div>
      ) : tab === "chart" ? (
        <ReportsChartPanel
          data={chartData}
          labels={{
            totalHours: t.reports?.totalHours || "Total hours",
            billableHours: t.reports?.billableHours || "Billable hours",
            nonBillableHours: t.reports?.nonBillableHours || "Non-billable hours",
            totalIncome: t.reports?.totalIncome || "Total income",
            chart: t.reports?.chartTitle || "Activity chart",
            totalSeconds: t.reports?.totalSeconds || "Total seconds",
          }}
        />
      ) : (
        <ReportsTablePanel
          data={tableData}
          dayDetails={dayDetails}
          openDay={openDay}
          onToggleDay={(day) => void handleToggleDay(day)}
          onExport={(type) => void handleExport(type)}
          exportState={exportState}
          labels={{
            exportExcel: t.reports?.exportExcel || "Export Excel",
            exportPdf: t.reports?.exportPdf || "Export PDF",
            date: t.reports?.date || "Date",
            billableHours: t.reports?.billableHours || "Billable hours",
            nonBillableHours: t.reports?.nonBillableHours || "Non-billable hours",
            totalHours: t.reports?.totalHours || "Total hours",
            totalIncome: t.reports?.totalIncome || "Total income",
            details: t.reports?.details || "Details",
            total: t.reports?.total || "Total",
            name: t.reports?.name || "Name",
            clientsTable: t.reports?.clientsTable || "Clients",
            projectsTable: t.reports?.projectsTable || "Projects",
            tagsTable: t.reports?.tagsTable || "Tags",
            noDescription: t.timesheet?.emptyDescription || "No description",
          }}
        />
      )}
    </div>
  );
}
