"use client";

import { useState, useMemo, useCallback, useEffect } from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { Plus, Loader2 } from "lucide-react";
import { CityTable } from "./city-table";
import { AddCityDialog } from "./add-city-dialog";
import { EditCityDialog } from "./edit-city-dialog";
import { DeleteCityDialog } from "./delete-city-dialog";
import {
  type City,
  type State,
} from "@/features/locations/services/locations.service";
import { useToastEnhanced } from "@/hooks/use-toast-enhanced";
import {
  getCitiesAction,
  createCityAction,
  updateCityAction,
  deleteCityAction,
} from "@/features/locations/actions/cities-actions";
import { getStatesAction } from "@/features/locations/actions/states-actions";
import type { LengthAwarePaginator } from "@/core/api";
import type { City as ApiCity, State as ApiState } from "@/core/api";

/**
 * Map API City to UI City interface
 */
function mapApiCityToCity(apiCity: any, states: State[]): City {
  const state = states.find((s) => s.id === String(apiCity.state_id));
  return {
    id: String(apiCity.id),
    stateId: String(apiCity.state_id),
    stateName: state ? state.name : `State ${apiCity.state_id}`,
    name: apiCity.name,
    status: apiCity.status === "active" ? "active" : "inactive",
    createdAt: apiCity.created_at || "",
    updatedAt: apiCity.updated_at || "",
  };
}

/**
 * Map API State to UI State interface (copied from StatesClient for internal use)
 */
function mapApiStateToState(apiState: any): State {
  return {
    id: String(apiState.id),
    name: apiState.name,
    status: apiState.status === "active" ? "active" : "inactive",
    createdAt: apiState.created_at || "",
    updatedAt: apiState.updated_at || "",
  };
}

interface CitiesClientProps {
  initialCitiesData?: LengthAwarePaginator<ApiCity>;
  initialStatesData?: LengthAwarePaginator<ApiState>;
  initialCitiesSearch?: string;
  initialCitiesPage?: number;
  initialStatesSearch?: string;
  initialStatesPage?: number;
}

export function CitiesClient({
  initialCitiesData,
  initialStatesData,
  initialCitiesSearch = "",
  initialCitiesPage = 1,
  initialStatesSearch = "",
  initialStatesPage = 1,
}: CitiesClientProps) {
  const toast = useToastEnhanced();
  const [currentTab, setCurrentTab] = useState("all");
  const [isLoading, setIsLoading] = useState(
    !(initialCitiesData && initialStatesData)
  );

  const [states, setStates] = useState<State[]>(
    initialStatesData ? initialStatesData.data.map(mapApiStateToState) : []
  );
  const [cities, setCities] = useState<City[]>(
    initialCitiesData
      ? initialCitiesData.data.map((c: any) =>
          mapApiCityToCity(
            c,
            initialStatesData?.data.map(mapApiStateToState) || []
          )
        )
      : []
  );
  const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
  const [editingCity, setEditingCity] = useState<City | null>(null);
  const [deletingCity, setDeletingCity] = useState<City | null>(null);

  const loadData = useCallback(async () => {
    setIsLoading(true);
    try {
      // 1. Fetch States first (needed for mapping city stateId to stateName)
      const statesResult = await getStatesAction();
      let currentStates: State[] = [];

      if (statesResult.success && statesResult.data) {
        currentStates = statesResult.data.data.map(mapApiStateToState);
        setStates(currentStates);
      } else {
        toast.error({
          title: "Error",
          description: statesResult.error || "Failed to load states",
        });
      }

      // 2. Fetch Cities
      const citiesResult = await getCitiesAction();
      if (citiesResult.success && citiesResult.data) {
        const mappedCities = citiesResult.data.data.map((c: any) =>
          mapApiCityToCity(c, currentStates)
        );
        setCities(mappedCities);
      } else {
        toast.error({
          title: "Error",
          description: citiesResult.error || "Failed to load cities",
        });
      }
    } catch {
      toast.error({
        title: "Error",
        description: "An unexpected error occurred",
      });
    } finally {
      setIsLoading(false);
    }
  }, [toast]);

  useEffect(() => {
    const hasInitial = !!initialCitiesData && !!initialStatesData;
    const isInitialQuery =
      initialCitiesSearch === "" &&
      initialCitiesPage === 1 &&
      initialStatesSearch === "" &&
      initialStatesPage === 1;
    if (hasInitial && isInitialQuery) return;
    loadData();
  }, [
    loadData,
    initialCitiesData,
    initialStatesData,
    initialCitiesSearch,
    initialCitiesPage,
    initialStatesSearch,
    initialStatesPage,
  ]);

  const activeStates = useMemo(
    () => states.filter((s) => s.status === "active"),
    [states]
  );

  const activeCities = useMemo(
    () => cities.filter((c) => c.status === "active"),
    [cities]
  );
  const inactiveCities = useMemo(
    () => cities.filter((c) => c.status === "inactive"),
    [cities]
  );

  const handleTabChange = (value: string) => {
    setCurrentTab(value);
  };

  const handleAddCity = useCallback(
    async (stateId: string, name: string) => {
      try {
        const result = await createCityAction({
          name,
          state_id: parseInt(stateId),
          status: "active",
        });

        if (result.success) {
          toast.success({
            title: "City Added",
            description: `${name} has been added successfully.`,
          });
          setIsAddDialogOpen(false);
          loadData();
          return true;
        }

        toast.error({
          title: "Failed to Add City",
          description: result.error || "An error occurred while adding city.",
        });
      } catch {
        toast.error({
          title: "Error",
          description: "An unexpected error occurred.",
        });
      }
      return false;
    },
    [toast, loadData]
  );

  const handleEditCity = useCallback(
    async (id: string, stateId: string, name: string) => {
      try {
        const result = await updateCityAction(parseInt(id), {
          name,
          state_id: parseInt(stateId),
          status: "active",
        });

        if (result.success) {
          toast.success({
            title: "City Updated",
            description: `${name} has been updated successfully.`,
          });
          setEditingCity(null);
          loadData();
          return true;
        }

        toast.error({
          title: "Failed to Update City",
          description: result.error || "An error occurred while updating city.",
        });
      } catch {
        toast.error({
          title: "Error",
          description: "An unexpected error occurred.",
        });
      }
      return false;
    },
    [toast, loadData]
  );

  const handleToggleStatus = useCallback(
    async (city: City) => {
      try {
        const newStatus = city.status === "active" ? "inactive" : "active";
        const result = await updateCityAction(parseInt(city.id), {
          name: city.name,
          state_id: parseInt(city.stateId),
          status: newStatus,
        });

        if (result.success) {
          loadData();
          const action = newStatus === "active" ? "activated" : "deactivated";
          toast.success({
            title: `City ${action.charAt(0).toUpperCase() + action.slice(1)}`,
            description: `${city.name} has been ${action}.`,
          });
        } else {
          toast.error({
            title: "Error",
            description: result.error || "Failed to toggle status.",
          });
        }
      } catch {
        toast.error({
          title: "Error",
          description: "An unexpected error occurred.",
        });
      }
    },
    [toast, loadData]
  );

  const handleDeleteCity = useCallback(async () => {
    if (!deletingCity) return;

    try {
      const result = await deleteCityAction(parseInt(deletingCity.id));
      if (result.success) {
        toast.success({
          title: "City Deleted",
          description: `${deletingCity.name} has been deleted.`,
        });
        loadData();
      } else {
        toast.error({
          title: "Error",
          description: result.error || "Failed to delete city.",
        });
      }
    } catch {
      toast.error({
        title: "Error",
        description: "An unexpected error occurred.",
      });
    }
    setDeletingCity(null);
  }, [deletingCity, toast, loadData]);

  const getDisplayCities = () => {
    switch (currentTab) {
      case "active":
        return activeCities;
      case "inactive":
        return inactiveCities;
      default:
        return cities;
    }
  };

  return (
    <section aria-labelledby="cities-heading" className="admin-section">
      <header className="admin-page-header flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 id="cities-heading" className="admin-page-title">
            Cities
          </h1>
          <p className="admin-page-description">
            Manage cities for your platform coverage.
          </p>
        </div>
        <Button
          onClick={() => setIsAddDialogOpen(true)}
          className="w-full sm:w-auto"
        >
          <Plus className="mr-2 h-4 w-4" aria-hidden="true" />
          Add City
        </Button>
      </header>

      {isLoading ? (
        <div className="flex flex-col items-center justify-center py-24 gap-4 animate-in fade-in duration-500">
          <div className="p-3 bg-primary/5 rounded-full ring-8 ring-primary/2">
            <Loader2 className="h-10 w-10 text-primary animate-spin" />
          </div>
          <div className="flex flex-col items-center gap-1">
            <h3 className="text-lg font-semibold text-foreground">
              Loading Cities
            </h3>
            <p className="text-sm text-muted-foreground">
              Fetching data from server...
            </p>
          </div>
        </div>
      ) : (
        <Tabs
          value={currentTab}
          onValueChange={handleTabChange}
          className="w-full"
        >
          <TabsList className="mb-6 h-auto p-1.5 bg-muted/50 rounded-xl border border-border/50">
            <TabsTrigger
              value="all"
              className="rounded-lg data-[state=active]:bg-background data-[state=active]:shadow-sm px-4 py-2"
            >
              All ({cities.length})
            </TabsTrigger>
            <TabsTrigger
              value="active"
              className="rounded-lg data-[state=active]:bg-background data-[state=active]:shadow-sm px-4 py-2"
            >
              Active ({activeCities.length})
            </TabsTrigger>
            <TabsTrigger
              value="inactive"
              className="rounded-lg data-[state=active]:bg-background data-[state=active]:shadow-sm px-4 py-2"
            >
              Inactive ({inactiveCities.length})
            </TabsTrigger>
          </TabsList>

          <TabsContent value="all" className="mt-0">
            <CityTable
              cities={getDisplayCities()}
              onEdit={setEditingCity}
              onDelete={setDeletingCity}
              onToggleStatus={handleToggleStatus}
            />
          </TabsContent>

          <TabsContent value="active" className="mt-0">
            <CityTable
              cities={getDisplayCities()}
              onEdit={setEditingCity}
              onDelete={setDeletingCity}
              onToggleStatus={handleToggleStatus}
            />
          </TabsContent>

          <TabsContent value="inactive" className="mt-0">
            <CityTable
              cities={getDisplayCities()}
              onEdit={setEditingCity}
              onDelete={setDeletingCity}
              onToggleStatus={handleToggleStatus}
            />
          </TabsContent>
        </Tabs>
      )}

      <AddCityDialog
        states={activeStates}
        open={isAddDialogOpen}
        onOpenChange={setIsAddDialogOpen}
        onAdd={handleAddCity}
      />

      <EditCityDialog
        city={editingCity}
        states={activeStates}
        open={!!editingCity}
        onOpenChange={(open) => !open && setEditingCity(null)}
        onSave={handleEditCity}
      />

      <DeleteCityDialog
        city={deletingCity}
        open={!!deletingCity}
        onOpenChange={(open) => !open && setDeletingCity(null)}
        onConfirm={handleDeleteCity}
      />
    </section>
  );
}
