import {Eye, EyeOff, RefreshCcw} from 'lucide-react';
import {useEffect, useMemo, useState} from 'react';

import {
  listAdminWorkVisibility,
  updateAdminWorkVisibility,
} from '../api/adminApiClient';
import type {AdminWorkVisibilityEntryPayload} from '../api/adminApiTypes';
import {useAdminWriteConfirm} from '../components/useAdminWriteConfirm';
import {handlePageError} from './pageUtils';

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

const sourceLabels: Record<string, string> = {
  puzzle: '拼图',
  'puzzle-clear': '拼消消',
  'custom-world': '自定义世界',
  'jump-hop': '跳一跳',
  'wooden-fish': '敲木鱼',
  match3d: '抓大鹅',
  'square-hole': '方洞挑战',
  'visual-novel': '视觉小说',
  'big-fish': '大鱼吃小鱼',
  'bark-battle': '汪汪声浪',
};

export function AdminWorkVisibilityPage({
  token,
  onUnauthorized,
}: AdminWorkVisibilityPageProps) {
  const [entries, setEntries] = useState<AdminWorkVisibilityEntryPayload[]>([]);
  const [keyword, setKeyword] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [savingKey, setSavingKey] = useState('');
  const [errorMessage, setErrorMessage] = useState('');
  const {confirmWrite, confirmDialog} = useAdminWriteConfirm();

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

  const filteredEntries = useMemo(() => {
    const normalizedKeyword = keyword.trim().toLowerCase();
    if (!normalizedKeyword) {
      return entries;
    }
    return entries.filter((entry) =>
      [
        entry.sourceType,
        sourceLabels[entry.sourceType] ?? '',
        entry.title,
        entry.subtitle,
        entry.authorDisplayName,
        entry.publicWorkCode,
        entry.profileId,
        entry.workId,
      ]
        .join(' ')
        .toLowerCase()
        .includes(normalizedKeyword),
    );
  }, [entries, keyword]);

  async function refreshEntries() {
    setIsLoading(true);
    setErrorMessage('');
    try {
      const response = await listAdminWorkVisibility(token);
      setEntries(sortEntries(response.entries));
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setErrorMessage);
    } finally {
      setIsLoading(false);
    }
  }

  async function handleToggle(entry: AdminWorkVisibilityEntryPayload) {
    const nextVisible = !entry.visible;
    const target = entry.title.trim() || entry.publicWorkCode || entry.profileId;
    const confirmed = await confirmWrite({
      action: nextVisible ? '显示作品' : '隐藏作品',
      target,
    });
    if (!confirmed) {
      return;
    }

    const rowKey = buildEntryKey(entry);
    setSavingKey(rowKey);
    setErrorMessage('');
    try {
      const response = await updateAdminWorkVisibility(token, {
        sourceType: entry.sourceType,
        profileId: entry.profileId,
        visible: nextVisible,
      });
      upsertEntry(response.entry);
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setErrorMessage);
    } finally {
      setSavingKey('');
    }
  }

  function upsertEntry(next: AdminWorkVisibilityEntryPayload) {
    setEntries((current) =>
      sortEntries([
        ...current.filter((entry) => buildEntryKey(entry) !== buildEntryKey(next)),
        next,
      ]),
    );
  }

  return (
    <section className="admin-page admin-page-wide">
      <div className="admin-page-heading">
        <div>
          <h2>作品可见性</h2>
        </div>
        <button
          className="admin-secondary-button"
          disabled={isLoading}
          type="button"
          onClick={refreshEntries}
        >
          <RefreshCcw size={17} aria-hidden="true" />
          <span>{isLoading ? '刷新中' : '刷新'}</span>
        </button>
      </div>

      <section className="admin-panel">
        <label className="admin-field">
          <span>搜索</span>
          <input
            placeholder="标题 / 作者 / 公开码 / profileId"
            value={keyword}
            onChange={(event) => setKeyword(event.target.value)}
          />
        </label>

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

        <div className="admin-table-wrap">
          <table className="admin-table admin-table-wide">
            <thead>
              <tr>
                <th>玩法</th>
                <th>作品</th>
                <th>作者</th>
                <th>公开码</th>
                <th>更新时间</th>
                <th>状态</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              {filteredEntries.map((entry) => {
                const rowKey = buildEntryKey(entry);
                const isSaving = savingKey === rowKey;
                return (
                  <tr key={rowKey}>
                    <td>
                      <span className="admin-tag">
                        {sourceLabels[entry.sourceType] ?? entry.sourceType}
                      </span>
                    </td>
                    <td>
                      <strong>{entry.title || entry.profileId}</strong>
                      <small>{entry.subtitle || entry.profileId}</small>
                    </td>
                    <td>
                      {entry.authorDisplayName || '玩家'}
                      <small>{entry.ownerUserId}</small>
                    </td>
                    <td>
                      <span className="admin-table-cell-ellipsis">
                        {entry.publicWorkCode}
                      </span>
                      <small>{entry.profileId}</small>
                    </td>
                    <td>{formatMicros(entry.updatedAtMicros)}</td>
                    <td>
                      <span
                        className={
                          entry.visible
                            ? 'admin-status admin-status-ok'
                            : 'admin-status admin-status-error'
                        }
                      >
                        {entry.visible ? '显示' : '隐藏'}
                      </span>
                    </td>
                    <td>
                      <button
                        className={
                          entry.visible
                            ? 'admin-danger-button'
                            : 'admin-secondary-button'
                        }
                        disabled={isSaving}
                        type="button"
                        onClick={() => handleToggle(entry)}
                      >
                        {entry.visible ? (
                          <EyeOff size={16} aria-hidden="true" />
                        ) : (
                          <Eye size={16} aria-hidden="true" />
                        )}
                        <span>
                          {isSaving
                            ? '处理中'
                            : entry.visible
                              ? '隐藏'
                              : '显示'}
                        </span>
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>

        {!isLoading && filteredEntries.length === 0 ? (
          <div className="admin-empty-state">暂无作品</div>
        ) : null}
      </section>

      {confirmDialog}
    </section>
  );
}

function sortEntries(entries: AdminWorkVisibilityEntryPayload[]) {
  return [...entries].sort((left, right) => {
    const timeCompare = right.updatedAtMicros - left.updatedAtMicros;
    if (timeCompare !== 0) {
      return timeCompare;
    }
    const sourceCompare = left.sourceType.localeCompare(right.sourceType);
    if (sourceCompare !== 0) {
      return sourceCompare;
    }
    return left.profileId.localeCompare(right.profileId);
  });
}

function buildEntryKey(entry: AdminWorkVisibilityEntryPayload) {
  return `${entry.sourceType}:${entry.profileId}`;
}

function formatMicros(value: number) {
  if (!Number.isFinite(value)) {
    return '-';
  }
  const date = new Date(Math.floor(value / 1000));
  if (!Number.isFinite(date.getTime())) {
    return '-';
  }
  return date.toLocaleString('zh-CN', {hour12: false});
}
