import {
  BarChart3,
  CheckCircle2,
  ClipboardCheck,
  Command,
  ChartNoAxesCombined,
  LayoutGrid,
  LogOut,
  Moon,
  Pause,
  Play,
  Plus,
  Repeat,
  Search,
  Shield,
  Sun,
  Timer,
  UserCog,
  UserCircle,
} from "lucide-react";
import { FormEvent, MouseEvent, useEffect, useMemo, useState } from "react";
import { useShallow } from "zustand/react/shallow";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Separator } from "@/components/ui/separator";
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInset,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarProvider,
  SidebarTrigger,
} from "@/components/ui/sidebar";
import { usePreferencesStore } from "@/stores/preferences/preferences-provider";

import { cn } from "./lib/utils";
import { ApiError, getCurrentUser, logout, lookupTicket } from "./api";
import { formatTimer } from "./format";
import { activeElapsedMs, pauseEntry, readStoredTimers, resumeEntry, storageKeyForUser, ticketPattern, type TimerEntry } from "./timers";
import { AdminUsersPage } from "./views/AdminUsersPage";
import { AnalysisPage } from "./views/AnalysisPage";
import { LoginPage } from "./views/LoginPage";
import { MonthlyClosePage } from "./views/MonthlyClosePage";
import { ProfilePage } from "./views/ProfilePage";
import { RecurringBillingsPage } from "./views/RecurringBillingsPage";
import { StatisticsPage } from "./views/StatisticsPage";
import { TicketDetailPage } from "./views/TicketDetailPage";
import { TimerPage } from "./views/TimerPage";
import type { AuthUser, PeriodType } from "./types";
import type { Dispatch, SetStateAction } from "react";

function routeFromPath(pathname: string) {
  const periodTicketMatch = pathname.match(/^\/analysis\/(month|day)\/([^/]+)\/tickets\/(\d+)$/);

  if (periodTicketMatch) {
    return {
      page: "ticket" as const,
      periodType: periodTicketMatch[1] as PeriodType,
      period: periodTicketMatch[2],
      ticketId: periodTicketMatch[3],
    };
  }

  const legacyTicketMatch = pathname.match(/^\/analysis\/(\d{4}-\d{2})\/tickets\/(\d+)$/);

  if (legacyTicketMatch) {
    return {
      page: "ticket" as const,
      periodType: "month" as const,
      period: legacyTicketMatch[1],
      ticketId: legacyTicketMatch[2],
    };
  }

  if (pathname.startsWith("/analysis")) {
    return { page: "analysis" as const };
  }

  if (pathname.startsWith("/statistics")) {
    return { page: "statistics" as const };
  }

  if (pathname.startsWith("/monthly-close")) {
    return { page: "monthly-close" as const };
  }

  if (pathname.startsWith("/recurring")) {
    return { page: "recurring" as const };
  }

  if (pathname.startsWith("/admin/users")) {
    return { page: "admin-users" as const };
  }

  if (pathname.startsWith("/profile")) {
    return { page: "profile" as const };
  }

  return { page: "timer" as const };
}

function useAppRouter() {
  const [path, setPath] = useState("/timer");

  useEffect(() => {
    const update = () => setPath(window.location.pathname);
    update();
    window.addEventListener("popstate", update);
    return () => window.removeEventListener("popstate", update);
  }, []);

  function navigate(to: string) {
    window.history.pushState({}, "", to);
    setPath(window.location.pathname);
  }

  function navHandler(to: string) {
    return (event: MouseEvent<HTMLAnchorElement>) => {
      event.preventDefault();
      navigate(to);
    };
  }

  return {
    path,
    route: useMemo(() => routeFromPath(path), [path]),
    navigate,
    navHandler,
  };
}

function ThemeSwitcher() {
  const { themeMode, setPreference } = usePreferencesStore(
    useShallow((state) => ({
      themeMode: state.values.theme_mode,
      setPreference: state.setPreference,
    })),
  );

  function cycleTheme() {
    setPreference("theme_mode", themeMode === "dark" ? "light" : "dark");
  }

  return (
    <Button variant="default" size="icon" aria-label="Farbschema wechseln" onClick={cycleTheme}>
      <Sun className="hidden dark:block" />
      <Moon className="block dark:hidden" />
    </Button>
  );
}

type QuickTimerStarterProps = {
  className?: string;
  inputId: string;
  onStartTimer: (ticketNumber: string) => Promise<boolean>;
};

function QuickTimerStarter({ className, inputId, onStartTimer }: QuickTimerStarterProps) {
  const [ticketNumber, setTicketNumber] = useState("");
  const trimmedTicketNumber = ticketNumber.trim();
  const hasInvalidTicket = trimmedTicketNumber.length > 0 && !ticketPattern.test(trimmedTicketNumber);

  async function submit(event: FormEvent) {
    event.preventDefault();

    if (await onStartTimer(trimmedTicketNumber)) {
      setTicketNumber("");
    }
  }

  return (
    <form className={cn("flex min-w-0 items-center gap-2", className)} onSubmit={submit}>
      <label className="sr-only" htmlFor={inputId}>
        Ticketnummer fuer neuen Timer
      </label>
      <Input
        id={inputId}
        className={cn("h-8 min-w-0 bg-background", hasInvalidTicket && "border-destructive focus-visible:border-destructive")}
        placeholder="Ticket#123456"
        value={ticketNumber}
        onChange={(event) => setTicketNumber(event.currentTarget.value)}
      />
      <Button type="submit" size="sm" className="h-8 shrink-0">
        <Plus className="size-3.5" />
        <span className="hidden sm:inline">Timer starten</span>
        <span className="sm:hidden">Start</span>
      </Button>
    </form>
  );
}

type SidebarTimersProps = {
  timers: TimerEntry[];
  selectedTimerId: string | null;
  setSelectedTimerId: Dispatch<SetStateAction<string | null>>;
  setTimers: Dispatch<SetStateAction<TimerEntry[]>>;
  tick: number;
  onOpenTimer: () => void;
};

function SidebarTimers({ timers, selectedTimerId, setSelectedTimerId, setTimers, tick, onOpenTimer }: SidebarTimersProps) {
  const sortedTimers = useMemo(
    () =>
      [...timers].sort((first, second) => {
        if (first.phase === second.phase) {
          return first.ticketNumber.localeCompare(second.ticketNumber);
        }

        return first.phase === "running" ? -1 : 1;
      }),
    [timers],
  );
  const runningTimer = timers.find((timer) => timer.phase === "running") ?? null;

  function toggleTimer(timerId: string) {
    const timer = timers.find((entry) => entry.id === timerId);

    if (!timer) {
      return;
    }

    const now = Date.now();
    setSelectedTimerId(timerId);
    setTimers((current) =>
      current.map((entry) => {
        if (entry.id !== timerId) {
          return pauseEntry(entry, now);
        }

        return timer.phase === "running" ? pauseEntry(entry, now) : resumeEntry(entry, now);
      }),
    );
  }

  return (
    <SidebarGroup className="pt-0 group-data-[collapsible=icon]:hidden">
      <SidebarGroupLabel className="h-6 px-2 text-xs">Timer</SidebarGroupLabel>
      <SidebarGroupContent>
        <div className="mx-2 rounded-md border bg-card/70 p-2 shadow-xs">
          <div className="mb-1 flex items-center justify-between gap-2">
            <span className="truncate text-xs font-medium text-muted-foreground">
              {runningTimer ? "Aktuell aktiv" : timers.length > 0 ? "Bereit" : "Kein Timer"}
            </span>
            {runningTimer ? <span className="size-2 rounded-full bg-emerald-500" aria-hidden="true" /> : null}
          </div>

          {sortedTimers.length === 0 ? (
            <p className="px-1 py-1 text-xs text-muted-foreground">Noch keine Timer gestartet.</p>
          ) : (
            <div className="max-h-52 space-y-1 overflow-y-auto pr-1">
              {sortedTimers.map((timer) => {
                const elapsed = Math.floor(activeElapsedMs(timer, tick) / 1000);
                const isSelected = selectedTimerId === timer.id;
                const isRunning = timer.phase === "running";

                return (
                  <div
                    key={timer.id}
                    className={cn(
                      "flex items-center gap-1.5 rounded-md border px-2 py-1.5",
                      isSelected ? "border-primary/55 bg-accent/35" : "border-transparent bg-background/60",
                    )}
                  >
                    <button
                      type="button"
                      className="min-w-0 flex-1 text-left"
                      onClick={() => {
                        setSelectedTimerId(timer.id);
                        onOpenTimer();
                      }}
                    >
                      <span className="flex min-w-0 items-center gap-1.5">
                        <span className={cn("size-1.5 rounded-full", isRunning ? "bg-emerald-500" : "bg-muted-foreground/50")} />
                        <span className="truncate text-xs font-medium">{timer.ticketNumber}</span>
                      </span>
                      {timer.organizationName ? (
                        <span className="block truncate text-[11px] leading-4 text-muted-foreground">
                          {timer.organizationName}
                        </span>
                      ) : null}
                      <span className="block font-mono text-[11px] font-semibold leading-4 tracking-normal text-muted-foreground">
                        {formatTimer(elapsed)}
                      </span>
                    </button>
                    <Button
                      type="button"
                      size="icon"
                      variant={isRunning ? "secondary" : "ghost"}
                      className="size-7 shrink-0"
                      onClick={() => toggleTimer(timer.id)}
                      aria-label={isRunning ? "Timer pausieren" : "Timer aktivieren"}
                    >
                      {isRunning ? <Pause className="size-3.5" /> : <Play className="size-3.5" />}
                    </Button>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </SidebarGroupContent>
    </SidebarGroup>
  );
}

export function App() {
  const { path, route, navHandler, navigate } = useAppRouter();
  const [currentUser, setCurrentUser] = useState<AuthUser | null>(null);
  const [authLoading, setAuthLoading] = useState(true);
  const [timers, setTimers] = useState<TimerEntry[]>([]);
  const [timersLoaded, setTimersLoaded] = useState(false);
  const [timerOwnerId, setTimerOwnerId] = useState<string | null>(null);
  const [selectedTimerId, setSelectedTimerId] = useState<string | null>(null);
  const [tick, setTick] = useState(Date.now());

  useEffect(() => {
    async function loadUser() {
      try {
        const result = await getCurrentUser();
        setCurrentUser(result.user);
      } catch (error) {
        if (!(error instanceof ApiError && error.status === 401)) {
          console.error(error);
        }
        setCurrentUser(null);
      } finally {
        setAuthLoading(false);
      }
    }

    void loadUser();
  }, []);

  useEffect(() => {
    if (!currentUser) {
      setTimers([]);
      setSelectedTimerId(null);
      setTimerOwnerId(null);
      setTimersLoaded(false);
      return;
    }

    setTimers(readStoredTimers(currentUser.id));
    setTimerOwnerId(currentUser.id);
    setTimersLoaded(true);
  }, [currentUser]);

  useEffect(() => {
    if (!currentUser || !timersLoaded || timerOwnerId !== currentUser.id) {
      return;
    }

    localStorage.setItem(storageKeyForUser(currentUser.id), JSON.stringify(timers));

    if (timers.length === 0) {
      setSelectedTimerId(null);
      return;
    }

    if (!selectedTimerId || !timers.some((timer) => timer.id === selectedTimerId)) {
      setSelectedTimerId(timers[0].id);
    }
  }, [currentUser, timers, selectedTimerId, timersLoaded, timerOwnerId]);

  useEffect(() => {
    if (!currentUser || !timersLoaded || timerOwnerId !== currentUser.id) {
      return;
    }

    const timersToHydrate = timers.filter((timer) => !timer.ticketLookupDone);

    if (timersToHydrate.length === 0) {
      return;
    }

    let cancelled = false;

    async function hydrateTimers() {
      const results = await Promise.all(
        timersToHydrate.map(async (timer) => {
          try {
            const result = await lookupTicket(timer.ticketNumber);
            return {
              id: timer.id,
              organizationName: result.ticket?.organization_name ?? result.ticket?.customer_name ?? null,
              workType: result.ticket?.work_type ?? null
            };
          } catch {
            return {
              id: timer.id,
              organizationName: null,
              workType: null
            };
          }
        })
      );

      if (cancelled) {
        return;
      }

      setTimers((current) =>
        current.map((timer) => {
          const result = results.find((entry) => entry.id === timer.id);

          if (!result) {
            return timer;
          }

          return {
            ...timer,
            organizationName: result.organizationName,
            workType: result.workType,
            ticketLookupDone: true
          };
        })
      );
    }

    void hydrateTimers();

    return () => {
      cancelled = true;
    };
  }, [currentUser, timers, timersLoaded, timerOwnerId]);

  useEffect(() => {
    const interval = window.setInterval(() => setTick(Date.now()), 500);
    return () => window.clearInterval(interval);
  }, []);

  async function startQuickTimer(rawTicketNumber: string) {
    const ticketNumber = rawTicketNumber.trim();

    if (!ticketPattern.test(ticketNumber)) {
      toast.error("Ticketnummer prüfen", {
        description: "Das Format muss Ticket#XXXXXX sein."
      });
      return false;
    }

    const existingTimer = timers.find((timer) => timer.ticketNumber === ticketNumber);
    const now = Date.now();

    if (existingTimer) {
      setTimers((current) =>
        current.map((timer) => (timer.id === existingTimer.id ? resumeEntry(timer, now) : pauseEntry(timer, now)))
      );
      setSelectedTimerId(existingTimer.id);
      toast.info("Bestehender Timer aktiviert", {
        description: ticketNumber
      });
      return true;
    }

    const ticketResult = await lookupTicket(ticketNumber).catch(() => ({ ticket: null }));

    const newTimer: TimerEntry = {
      id: crypto.randomUUID(),
      ticketNumber,
      organizationName: ticketResult.ticket?.organization_name ?? ticketResult.ticket?.customer_name ?? null,
      workType: ticketResult.ticket?.work_type ?? null,
      ticketLookupDone: true,
      startedAt: now,
      pausedTotalMs: 0,
      pausedAt: null,
      phase: "running"
    };

    setTimers((current) => [...current.map((timer) => pauseEntry(timer, now)), newTimer]);
    setSelectedTimerId(newTimer.id);
    toast.success("Timer gestartet", {
      description: ticketNumber
    });
    return true;
  }

  async function handleLogout() {
    await logout().catch(() => undefined);
    setCurrentUser(null);
    navigate("/timer");
  }

  if (authLoading) {
    return (
      <main className="grid min-h-screen place-items-center bg-background p-4 text-sm text-muted-foreground">
        TicketTracker wird geladen...
      </main>
    );
  }

  if (!currentUser) {
    return <LoginPage onLogin={setCurrentUser} />;
  }

  const navItems = [
    { href: "/timer", label: "Timer", icon: Timer, active: path.startsWith("/timer") || path === "/" },
    { href: "/analysis", label: "Auswertung", icon: BarChart3, active: path.startsWith("/analysis") },
    { href: "/monthly-close", label: "Monatsabschluss", icon: ClipboardCheck, active: path.startsWith("/monthly-close") },
    { href: "/statistics", label: "Statistiken", icon: ChartNoAxesCombined, active: path.startsWith("/statistics") },
    { href: "/recurring", label: "Fixe Abrechnung", icon: Repeat, active: path.startsWith("/recurring") },
    { href: "/profile", label: "Profil", icon: UserCog, active: path.startsWith("/profile") },
    ...(currentUser.role === "admin"
      ? [{ href: "/admin/users", label: "Benutzer", icon: Shield, active: path.startsWith("/admin/users") }]
      : []),
  ];
  const runningTimer = timers.find((timer) => timer.phase === "running") ?? null;
  const runningElapsedSeconds = runningTimer ? Math.floor(activeElapsedMs(runningTimer, tick) / 1000) : 0;

  return (
    <SidebarProvider
      defaultOpen
      style={
        {
          "--sidebar-width": "16rem",
        } as React.CSSProperties
      }
    >
      <Sidebar variant="sidebar" collapsible="icon">
        <SidebarHeader>
          <SidebarMenu>
            <SidebarMenuItem>
              <SidebarMenuButton asChild>
                <a href="/timer" onClick={navHandler("/timer")}>
                  <Command />
                  <span className="font-semibold text-base">TicketTracker</span>
                </a>
              </SidebarMenuButton>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarHeader>

        <SidebarContent>
          <SidebarGroup>
            <SidebarGroupContent className="flex flex-col gap-2">
              <SidebarMenu>
                <SidebarMenuItem className="flex items-center gap-2">
                  <SidebarMenuButton
                    asChild
                    tooltip="Session starten"
                    className="min-w-8 bg-primary text-primary-foreground duration-200 ease-linear hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground"
                  >
                    <a href="/timer" onClick={navHandler("/timer")}>
                      <Timer />
                      <span>Session starten</span>
                    </a>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              </SidebarMenu>
            </SidebarGroupContent>
          </SidebarGroup>

          <SidebarTimers
            timers={timers}
            selectedTimerId={selectedTimerId}
            setSelectedTimerId={setSelectedTimerId}
            setTimers={setTimers}
            tick={tick}
            onOpenTimer={() => navigate("/timer")}
          />

          <SidebarGroup>
            <SidebarGroupLabel>Workflows</SidebarGroupLabel>
            <SidebarGroupContent>
              <SidebarMenu>
                {navItems.map((item) => (
                  <SidebarMenuItem key={item.href}>
                    <SidebarMenuButton asChild tooltip={item.label} isActive={item.active}>
                      <a href={item.href} onClick={navHandler(item.href)}>
                        <item.icon />
                        <span>{item.label}</span>
                      </a>
                    </SidebarMenuButton>
                  </SidebarMenuItem>
                ))}
              </SidebarMenu>
            </SidebarGroupContent>
          </SidebarGroup>

        </SidebarContent>

        <SidebarFooter>
          <div className="mx-2 rounded-lg border bg-card p-3 text-sm shadow-xs group-data-[collapsible=icon]:hidden">
            <div className="mb-2 flex items-center gap-2 font-medium">
              <CheckCircle2 className="size-4 text-muted-foreground" />
              Abschluss
            </div>
            <p className="text-muted-foreground">Offene Bewertungen findest du im Monatsabschluss.</p>
          </div>
          <SidebarMenu>
            <SidebarMenuItem>
              <SidebarMenuButton tooltip="Worklog">
                <UserCircle />
                <span>Worklog lokal</span>
              </SidebarMenuButton>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarFooter>
      </Sidebar>

      <SidebarInset
        className={cn(
          "[html[data-content-layout=centered]_&>*]:mx-auto",
          "[html[data-content-layout=centered]_&>*]:w-full",
          "[html[data-content-layout=centered]_&>*]:max-w-screen-2xl",
          "[--dashboard-header-height:--spacing(12)]",
          "min-w-0 overflow-x-clip",
        )}
      >
        <header className="sticky top-0 z-50 flex h-12 shrink-0 items-center gap-2 border-b bg-background/80 backdrop-blur-md">
          <div className="flex w-full items-center justify-between px-3 sm:px-5 lg:px-6">
            <div className="flex min-w-0 items-center gap-2">
              <SidebarTrigger className="-ml-1" />
              <Separator orientation="vertical" className="mx-1 data-[orientation=vertical]:h-4 data-[orientation=vertical]:self-center" />
              <div className="hidden h-8 min-w-[160px] items-center gap-2 rounded-md px-2 text-sm text-muted-foreground lg:flex">
                <Search className="size-4" />
                <span>{currentUser.display_name}</span>
              </div>
              {runningTimer ? (
                <button
                  type="button"
                  className="flex h-8 min-w-0 items-center gap-1.5 rounded-md border bg-card px-2 text-xs shadow-xs"
                  onClick={() => {
                    setSelectedTimerId(runningTimer.id);
                    navigate("/timer");
                  }}
                >
                  <span className="size-1.5 rounded-full bg-emerald-500" aria-hidden="true" />
                  <span className="hidden max-w-28 truncate font-medium sm:inline">{runningTimer.ticketNumber}</span>
                  <span className="font-mono font-semibold tracking-normal">{formatTimer(runningElapsedSeconds)}</span>
                </button>
              ) : null}
              <div className="flex items-center gap-2 md:hidden">
                <LayoutGrid className="size-4" />
                <span className="truncate text-sm font-semibold">TicketTracker</span>
              </div>
            </div>
            <QuickTimerStarter
              inputId="quick-ticket-number-desktop"
              className="mx-3 hidden max-w-md flex-1 md:flex"
              onStartTimer={startQuickTimer}
            />
            <div className="flex items-center gap-2">
              <ThemeSwitcher />
              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button variant="ghost" size="icon" className="rounded-full border bg-background">
                    <UserCircle className="size-5" />
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-48">
                  <DropdownMenuLabel>
                    <span className="block truncate">{currentUser.display_name}</span>
                    <span className="block truncate text-xs font-normal text-muted-foreground">{currentUser.username}</span>
                  </DropdownMenuLabel>
                  <DropdownMenuSeparator />
                  <DropdownMenuItem onClick={() => navigate("/profile")}>
                    <UserCog className="size-4" />
                    Profil
                  </DropdownMenuItem>
                  <DropdownMenuItem onClick={() => void handleLogout()}>
                    <LogOut className="size-4" />
                    Abmelden
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </div>
          </div>
        </header>
        <div className="border-b bg-background/95 px-3 py-2 md:hidden">
          <QuickTimerStarter inputId="quick-ticket-number-mobile" onStartTimer={startQuickTimer} />
        </div>
        <main className="min-h-0 min-w-0 flex-1 overflow-x-hidden p-3 sm:p-4 md:p-5">
          <div className="mx-auto w-full max-w-screen-2xl">
            {route.page === "timer" ? (
              <TimerPage
                timers={timers}
                setTimers={setTimers}
                selectedTimerId={selectedTimerId}
                setSelectedTimerId={setSelectedTimerId}
                tick={tick}
              />
            ) : null}
            {route.page === "analysis" ? <AnalysisPage onNavigate={navigate} /> : null}
            {route.page === "monthly-close" ? <MonthlyClosePage onNavigate={navigate} /> : null}
            {route.page === "statistics" ? <StatisticsPage onNavigate={navigate} /> : null}
            {route.page === "recurring" ? <RecurringBillingsPage /> : null}
            {route.page === "profile" ? <ProfilePage currentUser={currentUser} onUserUpdated={setCurrentUser} /> : null}
            {route.page === "admin-users" && currentUser.role === "admin" ? <AdminUsersPage currentUser={currentUser} /> : null}
            {route.page === "admin-users" && currentUser.role !== "admin" ? (
              <TimerPage
                timers={timers}
                setTimers={setTimers}
                selectedTimerId={selectedTimerId}
                setSelectedTimerId={setSelectedTimerId}
                tick={tick}
              />
            ) : null}
            {route.page === "ticket" ? (
              <TicketDetailPage periodType={route.periodType} period={route.period} ticketId={route.ticketId} onNavigate={navigate} />
            ) : null}
          </div>
        </main>
      </SidebarInset>
    </SidebarProvider>
  );
}
