import {Eye, RefreshCcw, Search, X} from 'lucide-react';
import {FormEvent, useEffect, useMemo, useState} from 'react';

import {
  getAdminDatabaseTableRows,
  getAdminDatabaseTables,
} from '../api/adminApiClient';
import type {
  AdminDatabaseTableRowPayload,
  AdminDatabaseTableRowsResponse,
} from '../api/adminApiTypes';
import {handlePageError} from './pageUtils';

interface AdminDatabaseTablesPageProps {
  token: string;
  onUnauthorized: (message?: string) => void;
}

export function AdminDatabaseTablesPage({
  token,
  onUnauthorized,
}: AdminDatabaseTablesPageProps) {
  const [tables, setTables] = useState<string[]>([]);
  const [tableName, setTableName] = useState(() => readHashTableName());
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState('');
  const [limit, setLimit] = useState('100');
  const [result, setResult] = useState<AdminDatabaseTableRowsResponse | null>(null);
  const [detailRow, setDetailRow] = useState<AdminDatabaseTableRowPayload | null>(null);
  const [errorMessage, setErrorMessage] = useState('');
  const [isLoadingTables, setIsLoadingTables] = useState(false);
  const [isLoadingRows, setIsLoadingRows] = useState(false);

  useEffect(() => {
    void loadTables();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token]);

  useEffect(() => {
    const nextTableName = readHashTableName();
    if (nextTableName) {
      setTableName(nextTableName);
    }
    const handleHashChange = () => {
      const tableFromHash = readHashTableName();
      if (tableFromHash) {
        setTableName(tableFromHash);
        void refreshRows(tableFromHash);
      }
    };
    window.addEventListener('hashchange', handleHashChange);
    return () => window.removeEventListener('hashchange', handleHashChange);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (tables.length && !tableName) {
      setTableName(tables[0] ?? '');
    }
  }, [tableName, tables]);

  useEffect(() => {
    if (tableName) {
      void refreshRows(tableName);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [tableName]);

  const visibleColumns = useMemo(() => {
    const columns = result?.columns ?? [];
    if (columns.length) {
      return columns;
    }
    const firstRow = result?.rows[0];
    return firstRow ? Object.keys(firstRow.cells) : [];
  }, [result]);

  async function loadTables() {
    setIsLoadingTables(true);
    setErrorMessage('');
    try {
      const response = await getAdminDatabaseTables(token);
      setTables(response.tables);
      if (response.fetchErrors.length) {
        setErrorMessage(response.fetchErrors.join('；'));
      }
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setErrorMessage);
    } finally {
      setIsLoadingTables(false);
    }
  }

  async function refreshRows(nextTableName = tableName) {
    const normalizedTableName = nextTableName.trim();
    if (!normalizedTableName) {
      return;
    }
    setIsLoadingRows(true);
    setErrorMessage('');
    try {
      const response = await getAdminDatabaseTableRows(token, normalizedTableName, {
        search,
        filters,
        limit: parseLimit(limit),
      });
      setResult(response);
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setErrorMessage);
    } finally {
      setIsLoadingRows(false);
    }
  }

  function handleSearch(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    void refreshRows();
  }

  function handleTableChange(nextTableName: string) {
    setTableName(nextTableName);
    const nextHash = `#tables?table=${encodeURIComponent(nextTableName)}`;
    if (window.location.hash !== nextHash) {
      window.location.hash = nextHash;
    }
  }

  return (
    <section className="admin-page admin-page-wide">
      <div className="admin-page-heading">
        <div>
          <h2>表查询</h2>
          <p>SpacetimeDB 行数据</p>
        </div>
        <div className="admin-action-row">
          <button
            className="admin-secondary-button"
            disabled={isLoadingTables}
            type="button"
            onClick={() => void loadTables()}
          >
            <RefreshCcw size={17} aria-hidden="true" />
            <span>{isLoadingTables ? '刷新中' : '刷新表'}</span>
          </button>
          <button
            className="admin-primary-button"
            disabled={!tableName || isLoadingRows}
            type="button"
            onClick={() => void refreshRows()}
          >
            <Search size={17} aria-hidden="true" />
            <span>{isLoadingRows ? '查询中' : '查询'}</span>
          </button>
        </div>
      </div>

      <form className="admin-panel admin-form" onSubmit={handleSearch}>
        <div className="admin-table-query-grid">
          <label className="admin-field">
            <span>表</span>
            <select
              value={tableName}
              onChange={(event) => handleTableChange(event.target.value)}
            >
              {tableName && !tables.includes(tableName) ? (
                <option value={tableName}>{tableName}</option>
              ) : null}
              {tables.map((name) => (
                <option key={name} value={name}>
                  {name}
                </option>
              ))}
            </select>
          </label>
          <label className="admin-field">
            <span>关键词</span>
            <input
              placeholder="全部"
              value={search}
              onChange={(event) => setSearch(event.target.value)}
            />
          </label>
          <label className="admin-field">
            <span>筛选 JSON</span>
            <input
              placeholder='{"user_id":"u1"}'
              value={filters}
              onChange={(event) => setFilters(event.target.value)}
            />
          </label>
          <label className="admin-field admin-field-compact">
            <span>条数</span>
            <input
              inputMode="numeric"
              value={limit}
              onChange={(event) => setLimit(event.target.value)}
            />
          </label>
          <button className="admin-secondary-button" disabled={isLoadingRows} type="submit">
            <Search size={17} aria-hidden="true" />
            <span>{isLoadingRows ? '查询中' : '查询'}</span>
          </button>
        </div>
      </form>

      {errorMessage ? (
        <div className="admin-alert" role="status">
          {errorMessage}
        </div>
      ) : null}

      <section className="admin-panel">
        <div className="admin-panel-heading">
          <h3>{result?.tableName || tableName || '数据行'}</h3>
          <span>{result?.totalReturned ?? 0} 条</span>
        </div>
        <div className="admin-table-wrap">
          <table className="admin-table admin-table-wide">
            <thead>
              <tr>
                {visibleColumns.map((column) => (
                  <th key={column}>{column}</th>
                ))}
                <th>详情</th>
              </tr>
            </thead>
            <tbody>
              {result?.rows.length ? (
                result.rows.map((row, rowIndex) => (
                  <tr
                    key={buildRowKey(row, rowIndex)}
                    data-clickable="true"
                    onClick={() => setDetailRow(row)}
                  >
                    {visibleColumns.map((column) => (
                      <td key={column}>{formatCellValue(row.cells[column])}</td>
                    ))}
                    <td>
                      <button
                        className="admin-secondary-button"
                        type="button"
                        onClick={(event) => {
                          event.stopPropagation();
                          setDetailRow(row);
                        }}
                      >
                        <Eye size={16} aria-hidden="true" />
                        <span>详情</span>
                      </button>
                    </td>
                  </tr>
                ))
              ) : (
                <tr>
                  <td colSpan={Math.max(visibleColumns.length + 1, 1)}>暂无数据</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </section>

      {detailRow ? (
        <div className="admin-confirm-backdrop" role="presentation">
          <section className="admin-detail-panel" role="dialog" aria-modal="true">
            <div className="admin-panel-heading">
              <h3>行详情</h3>
              <button
                className="admin-ghost-button"
                title="关闭"
                type="button"
                onClick={() => setDetailRow(null)}
              >
                <X size={17} aria-hidden="true" />
              </button>
            </div>
            <pre className="admin-code-block">
              {JSON.stringify(detailRow.cells, null, 2)}
            </pre>
          </section>
        </div>
      ) : null}
    </section>
  );
}

function readHashTableName() {
  const hash = window.location.hash;
  const queryIndex = hash.indexOf('?');
  if (queryIndex < 0) {
    return '';
  }
  return new URLSearchParams(hash.slice(queryIndex + 1)).get('table')?.trim() ?? '';
}

function parseLimit(value: string) {
  const parsed = Number.parseInt(value.trim(), 10);
  return Number.isFinite(parsed) ? parsed : 100;
}

function buildRowKey(row: AdminDatabaseTableRowPayload, rowIndex: number) {
  const firstValue = Object.values(row.cells)[0];
  return `${rowIndex}-${String(firstValue ?? '')}`;
}

function formatCellValue(value: unknown) {
  if (value === null || typeof value === 'undefined' || value === '') {
    return '-';
  }
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
    return String(value);
  }
  return <pre className="admin-json-preview">{JSON.stringify(value, null, 2)}</pre>;
}
