/**
 * Directory Page
 *
 * Interactive company directory for facility tenants and visitors.
 * Features smart filtering with dynamically generated alphabet buttons,
 * presence-based status filtering, and auto-clearing unavailable selections.
 * Companies are sorted with present companies first for easy sign-out access.
 */

/* React hooks */
import { useState, useEffect, useMemo, useCallback } from "react";

/* UI Components */
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";

/* Kiosk Components */
import { CompanyCard } from "@/components/kiosk/company-card";

/* Types & Constants */
import { type Company } from "@/types/company";
import type { Room, FloorPlanWithRooms } from "@/types/floor-plan";

/* Context */
import { useKioskData } from "@/contexts/kiosk-data-context";

/* Services */
import { updateCompanyStatus } from "@/services/companies";

/* Constants */
import { LOADING_MESSAGES, ERROR_MESSAGES, EMPTY_MESSAGES, SECTION_HEADERS, FILTER_LABELS } from "@/constants/ui-text";

/* Filter state options: all companies, present only, or absent only */
type StatusFilter = "all" | "present" | "absent";

/**
 * Directory Component
 *
 * Manages filtering state and renders company directory with smart features:
 * - Dynamic alphabet generation (only shows letters that exist in data)
 * - Smart letter availability (disabled when no matches for current filter)
 * - Auto-clearing selections when they become invalid
 * - Sorted sections (present first for easy sign-out, then absent)
 * - Real-time updates via PocketBase subscriptions
 */
export function Directory() {
  const { companies, floorPlans, loading, error } = useKioskData();

  const [selectedLetter, setSelectedLetter] = useState<string | null>(null);
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [updatingCompanyId, setUpdatingCompanyId] = useState<string | null>(null);

  /**
   * Checks if a company matches the current status filter
   * Extracted to avoid duplication - used in both availableLetters and filteredCompanies
   */
  const matchesStatusFilter = useCallback(
    (company: Company) => {
      return (
        statusFilter === "all" ||
        (statusFilter === "present" && company.status === "present") ||
        (statusFilter === "absent" && company.status === "absent")
      );
    },
    [statusFilter],
  );

  /**
   * Handles toggling company status between present and absent
   * Updates via PocketBase API and real-time subscription auto-updates UI
   */
  const handleStatusToggle = useCallback(async (company: Company): Promise<void> => {
    const newStatus = company.status === "present" ? "absent" : "present";
    setUpdatingCompanyId(company.id);

    try {
      await updateCompanyStatus(company.id, newStatus);
      /* Real-time subscription will automatically update the UI */
    } catch (error) {
      console.error("Failed to update company status:", error);
      /* TODO: Could add error toast notification here */
    } finally {
      setUpdatingCompanyId(null);
    }
  }, []);

  /**
   * Creates lookup map for company locations
   * Prevents O(n*m) lookups when rendering company cards
   */
  const companyLocationMap = useMemo(() => {
    const map = new Map<string, { room: Room; floorPlan: FloorPlanWithRooms }>();

    for (const floorPlan of floorPlans) {
      for (const room of floorPlan.rooms) {
        if (room.company) {
          map.set(room.company, { room, floorPlan });
        }
      }
    }

    return map;
  }, [floorPlans]);

  /**
   * Generates dynamic alphabet from actual company data
   * Only displays letters that exist in the company list
   */
  const alphabet = useMemo(() => {
    const letters = new Set<string>();
    companies.forEach((company) => {
      const firstLetter = company.short_name.charAt(0).toUpperCase();
      letters.add(firstLetter);
    });
    return Array.from(letters).sort();
  }, [companies]);

  /**
   * Calculates which alphabet letters have companies for the current status filter
   * Returns Set for O(1) lookup when rendering alphabet buttons
   */
  const availableLetters = useMemo(() => {
    const letters = new Set<string>();

    companies.forEach((company) => {
      if (matchesStatusFilter(company)) {
        const firstLetter = company.short_name.charAt(0).toUpperCase();
        letters.add(firstLetter);
      }
    });

    return letters;
  }, [companies, matchesStatusFilter]);

  /**
   * Auto-clear selected letter when it becomes unavailable
   * Example: User has "M" selected, switches to "Prisutni" but no present
   * companies start with "M" - auto-clears to show all present companies
   */
  useEffect(() => {
    if (selectedLetter && !availableLetters.has(selectedLetter)) {
      setSelectedLetter(null);
    }
  }, [statusFilter, selectedLetter, availableLetters]);

  /* Filter companies by both letter selection and status filter */
  const filteredCompanies = useMemo(() => {
    return companies.filter((company) => {
      const matchesLetter = !selectedLetter || company.short_name.toUpperCase().startsWith(selectedLetter);
      return matchesLetter && matchesStatusFilter(company);
    });
  }, [companies, selectedLetter, matchesStatusFilter]);

  /* Separate and sort companies: present first (for easy sign-out), then absent */
  const presentCompanies = filteredCompanies
    .filter((c) => c.status === "present")
    .sort((a, b) => a.short_name.localeCompare(b.short_name));

  const absentCompanies = filteredCompanies
    .filter((c) => c.status === "absent")
    .sort((a, b) => a.short_name.localeCompare(b.short_name));

  /* Loading state */
  if (loading) {
    return (
      <main className="flex h-full items-center justify-center">
        <p className="text-muted-foreground">{LOADING_MESSAGES.companies}</p>
      </main>
    );
  }

  /* Error state */
  if (error) {
    return (
      <main className="flex h-full items-center justify-center">
        <p className="text-destructive">{ERROR_MESSAGES.generic}</p>
      </main>
    );
  }

  return (
    <main className="flex h-full flex-col gap-6">
      {/* Filter controls: Status filter and dynamic alphabet navigation */}
      <div className="flex items-center justify-center gap-8">
        {/* Status filter: All, Present, or Absent companies */}
        <div className="flex gap-2">
          <Button
            variant={statusFilter === "all" ? "default" : "outline"}
            onClick={() => setStatusFilter("all")}
            className="h-12"
          >
            {FILTER_LABELS.all}
          </Button>
          <Button
            variant={statusFilter === "present" ? "default" : "outline"}
            onClick={() => setStatusFilter("present")}
            className="h-12"
          >
            {FILTER_LABELS.present}
          </Button>
          <Button
            variant={statusFilter === "absent" ? "default" : "outline"}
            onClick={() => setStatusFilter("absent")}
            className="h-12"
          >
            {FILTER_LABELS.absent}
          </Button>
        </div>

        {/* Dynamic alphabet: Only shows letters that exist in company data */}
        <div className="flex gap-2">
          {alphabet.map((letter) => {
            const isAvailable = availableLetters.has(letter);
            const isSelected = selectedLetter === letter;

            return (
              <Button
                key={letter}
                variant={isSelected ? "default" : "outline"}
                disabled={!isAvailable}
                onClick={() => isAvailable && setSelectedLetter(isSelected ? null : letter)}
                className={`h-14 w-14 p-0 ${!isAvailable ? "cursor-not-allowed opacity-40" : ""}`}
              >
                {letter}
              </Button>
            );
          })}
        </div>
      </div>

      {/* Present companies grid (shown first for easy tenant sign-out) */}
      <div className="grid grid-cols-3 gap-4">
        {presentCompanies.map((company) => (
          <CompanyCard
            key={company.id}
            company={company}
            location={companyLocationMap.get(company.id) || null}
            isUpdating={updatingCompanyId === company.id}
            onStatusToggle={handleStatusToggle}
          />
        ))}
      </div>

      {/* Visual separator between present and absent sections */}
      {absentCompanies.length > 0 && presentCompanies.length > 0 && (
        <div className="relative flex items-center py-2">
          <Separator className="flex-1" />
          <span className="text-muted-foreground px-4 text-sm">{SECTION_HEADERS.absentCompanies}</span>
          <Separator className="flex-1" />
        </div>
      )}

      {/* Absent companies grid (shown below separator) */}
      {absentCompanies.length > 0 && (
        <div className="grid grid-cols-3 gap-4">
          {absentCompanies.map((company) => (
            <CompanyCard
              key={company.id}
              company={company}
              location={companyLocationMap.get(company.id) || null}
              isUpdating={updatingCompanyId === company.id}
              onStatusToggle={handleStatusToggle}
            />
          ))}
        </div>
      )}

      {/* Empty state: Shown when no companies match the filter criteria */}
      {filteredCompanies.length === 0 && (
        <div className="flex flex-1 items-center justify-center">
          <p className="text-muted-foreground">{EMPTY_MESSAGES.noCompanies}</p>
        </div>
      )}
    </main>
  );
}
