import { useEffect, useState } from 'react';
import { formatBytes } from '../app/application-state';
import { getDerivedCache } from '../app/derived-cache';
import {
  readStorageQuota,
  type DerivedCacheEntry,
  type StorageQuotaSnapshot,
} from '../storage';
import { Icon } from './Icon';

export function StoragePanel({ projectId }: { readonly projectId?: string }) {
  const [quota, setQuota] = useState<StorageQuotaSnapshot>();
  const [entries, setEntries] = useState<readonly DerivedCacheEntry[]>([]);
  const [mode, setMode] = useState<'opfs' | 'memory'>('memory');
  const [message, setMessage] = useState<string>();

  const refresh = async () => {
    const [nextQuota, cache] = await Promise.all([
      readStorageQuota(),
      getDerivedCache(),
    ]);
    setQuota(nextQuota);
    setMode(cache.mode);
    setEntries(await cache.list());
  };

  const runCacheAction = async (
    action: () => Promise<void>,
    success: string
  ) => {
    try {
      await action();
      await refresh();
      setMessage(success);
    } catch (error) {
      setMessage(
        error instanceof Error
          ? `Cache operation failed: ${error.message}`
          : 'Cache operation failed.'
      );
    }
  };

  useEffect(() => {
    const timer = globalThis.setTimeout(() => {
      void refresh().catch((error: unknown) => {
        setMessage(
          error instanceof Error
            ? error.message
            : 'Storage status is unavailable.'
        );
      });
    }, 0);
    return () => globalThis.clearTimeout(timer);
  }, []);

  const cachedBytes = entries.reduce(
    (total, entry) => total + entry.sizeBytes,
    0
  );
  const projectEntries = projectId
    ? entries.filter((entry) => entry.projectId === projectId)
    : [];

  return (
    <details
      className="capability-panel storage-panel"
      onToggle={(event) => {
        if (!event.currentTarget.open) return;
        void refresh().catch((error: unknown) => {
          setMessage(
            error instanceof Error
              ? error.message
              : 'Storage status is unavailable.'
          );
        });
      }}
    >
      <summary>
        <span>
          <Icon name="queue" />
          Derived cache
        </span>
        <span className="engine-pill">
          {formatBytes(cachedBytes)} · {mode.toUpperCase()}
        </span>
      </summary>
      <div className="storage-panel__body">
        <dl className="capability-grid">
          <div>
            <dt>Origin usage</dt>
            <dd>
              {quota?.usageBytes === undefined
                ? 'Not reported'
                : formatBytes(quota.usageBytes)}
            </dd>
          </div>
          <div>
            <dt>Origin quota</dt>
            <dd>
              {quota?.quotaBytes === undefined
                ? 'Not reported'
                : formatBytes(quota.quotaBytes)}
            </dd>
          </div>
          <div>
            <dt>Cached items</dt>
            <dd>{entries.length}</dd>
          </div>
        </dl>
        {entries.length > 0 ? (
          <ul className="cache-list">
            {entries.map((entry) => (
              <li key={entry.key}>
                <span className="stream-kind">{entry.kind}</span>
                <span>{formatBytes(entry.sizeBytes)}</span>
                <button
                  className="icon-action"
                  type="button"
                  aria-label={`Delete cached ${entry.kind}`}
                  onClick={() => {
                    void runCacheAction(async () => {
                      await (await getDerivedCache()).delete(entry.key);
                    }, `Deleted cached ${entry.kind}.`);
                  }}
                >
                  <Icon name="trash" />
                </button>
              </li>
            ))}
          </ul>
        ) : (
          <p className="section-intro">
            Preview proxies and generated frames may be cached here. Original
            source media is never added automatically.
          </p>
        )}
        <div className="storage-panel__actions">
          <button
            className="button button--secondary"
            type="button"
            disabled={entries.length === 0}
            onClick={() => {
              void runCacheAction(
                async () => (await getDerivedCache()).clear(),
                'Derived cache cleared.'
              );
            }}
          >
            <Icon name="trash" />
            Clear cache
          </button>
          <button
            className="button button--quiet"
            type="button"
            disabled={!projectId || projectEntries.length === 0}
            onClick={() => {
              if (!projectId) return;
              void runCacheAction(
                async () => {
                  await (await getDerivedCache()).clearProject(projectId);
                },
                `Cleared ${projectEntries.length} current-project cache item${projectEntries.length === 1 ? '' : 's'}.`
              );
            }}
          >
            Clear current project
          </button>
          <button
            className="button button--quiet"
            type="button"
            onClick={() =>
              void runCacheAction(
                async () => undefined,
                'Storage status refreshed.'
              )
            }
          >
            Refresh
          </button>
          {message ? <span role="status">{message}</span> : null}
        </div>
      </div>
    </details>
  );
}
