import type { AdminTableMeta, AdminTableSummary } from "@xtablo/shared-types";
import { useEffect, useState } from "react";
import { adminApi } from "../lib/api";

export type AdminRow = Record<string, string | boolean | null>;

function getErrorMessage(error: unknown, fallbackMessage: string) {
  if (typeof error === "object" && error !== null && "response" in error) {
    const response = error.response;
    if (
      typeof response === "object" &&
      response !== null &&
      "data" in response &&
      typeof response.data === "object" &&
      response.data !== null &&
      "error" in response.data &&
      typeof response.data.error === "string"
    ) {
      return response.data.error;
    }
  }

  return fallbackMessage;
}

export function useAdminTables() {
  const [tables, setTables] = useState<AdminTableSummary[]>([]);
  const [selectedTableId, setSelectedTableId] = useState<string | null>(null);
  const [meta, setMeta] = useState<AdminTableMeta | null>(null);
  const [rows, setRows] = useState<AdminRow[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let isMounted = true;

    const loadTables = async () => {
      try {
        const response = await adminApi.get<{ tables: AdminTableSummary[] }>("/admin/tables");
        if (!isMounted) {
          return;
        }

        setTables(response.data.tables);
        setSelectedTableId((currentValue) => currentValue ?? response.data.tables[0]?.id ?? null);
      } catch {
        if (isMounted) {
          setError("Failed to load admin tables");
        }
      }
    };

    void loadTables();

    return () => {
      isMounted = false;
    };
  }, []);

  useEffect(() => {
    let isMounted = true;

    const loadTableData = async () => {
      if (!selectedTableId) {
        setIsLoading(false);
        return;
      }

      setIsLoading(true);
      setError(null);

      try {
        const [metaResponse, rowsResponse] = await Promise.all([
          adminApi.get<AdminTableMeta>(`/admin/tables/${selectedTableId}/meta`),
          adminApi.get<{ rows: AdminRow[] }>(`/admin/tables/${selectedTableId}/rows`),
        ]);

        if (!isMounted) {
          return;
        }

        setMeta(metaResponse.data);
        setRows(rowsResponse.data.rows);
      } catch {
        if (isMounted) {
          setError("Failed to load admin table data");
          setMeta(null);
          setRows([]);
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    };

    void loadTableData();

    return () => {
      isMounted = false;
    };
  }, [selectedTableId]);

  const updateRow = async (rowId: string, changes: Partial<AdminRow>) => {
    if (!selectedTableId) {
      throw new Error("No admin table selected");
    }

    try {
      const response = await adminApi.patch<{ row: AdminRow }>(
        `/admin/tables/${selectedTableId}/rows/${rowId}`,
        changes
      );
      const updatedRow = response.data.row;

      setRows((currentRows) =>
        currentRows.map((row) => {
          if (String(row[meta?.primaryKey ?? "id"] ?? "") !== rowId) {
            return row;
          }

          return updatedRow;
        })
      );
      setError(null);

      return updatedRow;
    } catch (error) {
      const message = getErrorMessage(error, "Failed to update admin row");
      setError(message);
      throw new Error(message);
    }
  };

  return {
    error,
    isLoading,
    meta,
    rows,
    selectedTableId,
    setSelectedTableId,
    tables,
    updateRow,
  };
}
