'use client';

import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Loader2, AlertCircle, BarChart2, ChevronDown, ChevronRight } from 'lucide-react';
import Link from 'next/link';
import { fetchQuotaHistory, type QuotaLogEntry } from '@/lib/api';
import f from '@/components/shared/FormField.module.css';
import styles from './page.module.css';

const OPERATION_COST: Record<string, string> = {
  'videos.update': '50',
  'playlistItems.insert': '50',
  'playlistItems.delete': '50',
  'videos.list': '1',
  'playlistItems.list': '1',
  'playlists.list': '1',
  'channels.list': '1',
};

function relativeTime(iso: string) {
  const diff = Date.now() - new Date(iso).getTime();
  const s = Math.floor(diff / 1000);
  if (s < 60) return `${s}s ago`;
  const m = Math.floor(s / 60);
  if (m < 60) return `${m}m ago`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h ago`;
  return `${Math.floor(h / 24)}d ago`;
}

function formatDateTime(iso: string) {
  return new Date(iso).toLocaleString();
}

function operationLabel(op: string) {
  const labels: Record<string, string> = {
    'videos.update': 'Push to YouTube',
    'videos.list': 'Fetch video metadata',
    'playlistItems.list': 'List playlist items',
    'playlistItems.insert': 'Add to playlist',
    'playlistItems.delete': 'Remove from playlist',
    'playlists.list': 'List playlists',
    'channels.list': 'Fetch channel info',
  };
  return labels[op] ?? op;
}

const DAYS_OPTIONS = [
  { value: 1, label: 'Today' },
  { value: 7, label: 'Last 7 days' },
  { value: 30, label: 'Last 30 days' },
  { value: 90, label: 'Last 90 days' },
];

function groupByOperation(items: QuotaLogEntry[]) {
  const map = new Map<string, { count: number; units: number }>();
  for (const item of items) {
    const existing = map.get(item.operation) ?? { count: 0, units: 0 };
    map.set(item.operation, { count: existing.count + 1, units: existing.units + item.units });
  }
  return Array.from(map.entries())
    .map(([op, stats]) => ({ op, ...stats }))
    .sort((a, b) => b.units - a.units);
}

// ── Action group clustering ──────────────────────────────────────────────────

const ACTION_TYPE_LABELS: Record<string, string> = {
  channel_import: 'Channel Import',
  video_sync: 'Push to YouTube',
  video_refresh: 'Refresh from YouTube',
  playlist_sync: 'Playlist Sync',
  playlist_add: 'Add to Playlist',
  playlist_remove: 'Remove from Playlist',
};

interface ActionGroup {
  actionId: string | null;
  channelId: string | null;
  channelName: string | null;
  startTs: number;
  totalUnits: number;
  entries: QuotaLogEntry[];
  label: string;
  detail: string | null;
  videoId: string | null;
  youtubeVideoId: string | null;
}

function buildLabel(
  actionType: string | null,
  entries: QuotaLogEntry[],
): { label: string; detail: string | null; videoId: string | null; youtubeVideoId: string | null } {
  const label = (actionType && ACTION_TYPE_LABELS[actionType]) ?? operationLabel(entries[0]?.operation ?? '');

  if (actionType === 'video_sync' || actionType === 'video_refresh') {
    const e = entries.find((e) => e.videoTitle ?? e.videoId);
    return {
      label,
      detail: e?.videoTitle ?? e?.videoId ?? null,
      videoId: e?.videoId ?? null,
      youtubeVideoId: e?.youtubeVideoId ?? null,
    };
  }
  if (actionType === 'playlist_add' || actionType === 'playlist_remove') {
    const e = entries.find((e) => e.entityLabel);
    return { label, detail: e?.entityLabel ?? null, videoId: null, youtubeVideoId: null };
  }
  return { label, detail: null, videoId: null, youtubeVideoId: null };
}

function groupByActionId(items: QuotaLogEntry[]): ActionGroup[] {
  if (!items.length) return [];

  const map = new Map<string, ActionGroup>();

  for (const entry of items) {
    const key = entry.actionId ?? `ungrouped:${entry.id}`;
    const ts = new Date(entry.createdAt).getTime();

    if (!map.has(key)) {
      map.set(key, {
        actionId: entry.actionId,
        channelId: entry.channelId,
        channelName: entry.channelName,
        startTs: ts,
        totalUnits: 0,
        entries: [],
        label: '',
        detail: null,
        videoId: null,
        youtubeVideoId: null,
      });
    }

    const group = map.get(key)!;
    group.totalUnits += entry.units;
    group.entries.push(entry);
    if (ts < group.startTs) group.startTs = ts;
  }

  const groups = Array.from(map.values());

  for (const group of groups) {
    const actionType = group.entries[0]?.actionType ?? null;
    const { label, detail, videoId, youtubeVideoId } = buildLabel(actionType, group.entries);
    group.label = label;
    group.detail = detail;
    group.videoId = videoId;
    group.youtubeVideoId = youtubeVideoId;
    group.entries.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
  }

  const sorted = groups.sort((a, b) => b.startTs - a.startTs);
  return clusterVideoGroups(sorted);
}

// Merge action groups that share the same videoId and are within 60 seconds of each other.
// This handles the common case where a video push and playlist changes are logged as separate
// actionIds but belong to the same user-initiated save action.
function clusterVideoGroups(groups: ActionGroup[]): ActionGroup[] {
  const result: ActionGroup[] = [];
  const used = new Set<number>();

  for (let i = 0; i < groups.length; i++) {
    if (used.has(i)) continue;
    const g = groups[i];

    if (!g.videoId) {
      result.push(g);
      continue;
    }

    const toMerge: ActionGroup[] = [g];
    for (let j = i + 1; j < groups.length; j++) {
      if (used.has(j)) continue;
      const other = groups[j];
      if (other.videoId !== g.videoId) continue;
      // groups are sorted newest-first so g.startTs >= other.startTs
      if (g.startTs - other.startTs > 60_000) continue;
      toMerge.push(other);
      used.add(j);
    }

    if (toMerge.length === 1) {
      result.push(g);
    } else {
      const allEntries = toMerge
        .flatMap((m) => m.entries)
        .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
      const totalUnits = toMerge.reduce((s, m) => s + m.totalUnits, 0);
      const startTs = Math.min(...toMerge.map((m) => m.startTs));
      // Prefer the video_sync group's label if present; otherwise keep the first
      const primary = toMerge.find((m) => m.entries.some((e) => e.actionType === 'video_sync')) ?? toMerge[0];
      result.push({ ...primary, entries: allEntries, totalUnits, startTs });
    }
  }

  return result;
}

// ── Components ───────────────────────────────────────────────────────────────

function ActionGroupRow({ group }: { group: ActionGroup }) {
  const [open, setOpen] = useState(false);
  const startIso = new Date(group.startTs).toISOString();

  return (
    <div className={styles.groupBlock}>
      <button
        className={styles.groupHeader}
        onClick={() => setOpen((v) => !v)}
        aria-expanded={open}
      >
        <span className={styles.groupChevron}>
          {open ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
        </span>
        <span className={styles.groupTime} title={formatDateTime(startIso)}>
          {relativeTime(startIso)}
        </span>
        <span className={styles.groupLabel}>{group.label}</span>
        {group.detail && (
          group.videoId ? (
            <Link
              href={`/videos/${group.videoId}`}
              className={styles.groupDetail}
              onClick={(e) => e.stopPropagation()}
            >
              {group.detail}
              {group.youtubeVideoId && (
                <span className={styles.groupVideoId}>{group.youtubeVideoId}</span>
              )}
            </Link>
          ) : (
            <span className={styles.groupDetail}>{group.detail}</span>
          )
        )}
        <span className={styles.groupMeta}>
          {group.channelName && <span className={styles.groupChannel}>{group.channelName}</span>}
          <span className={styles.groupCalls}>{group.entries.length} call{group.entries.length !== 1 ? 's' : ''}</span>
          <span className={`${styles.groupUnits} ${group.totalUnits >= 50 ? styles.groupUnitsHigh : ''}`}>
            {group.totalUnits} units
          </span>
        </span>
      </button>

      {open && (
        <div className={styles.groupEntries}>
          <table className={styles.subTable}>
            <thead>
              <tr>
                <th>Time</th>
                <th>Operation</th>
                <th>Detail</th>
                <th className={styles.numCol}>Units</th>
              </tr>
            </thead>
            <tbody>
              {group.entries.map((entry) => (
                <tr key={entry.id} className={styles.subRow}>
                  <td className={styles.timeCell} title={formatDateTime(entry.createdAt)}>
                    {relativeTime(entry.createdAt)}
                  </td>
                  <td>
                    <span className={styles.opLabel}>{operationLabel(entry.operation)}</span>
                    <span className={styles.opCode}>{entry.operation}</span>
                  </td>
                  <td className={styles.detailCell}>
                    {entry.videoId ? (
                      <Link href={`/videos/${entry.videoId}`} className={styles.videoLink}>
                        {entry.videoTitle ?? entry.videoId}
                        {entry.youtubeVideoId && (
                          <span className={styles.groupVideoId}>{entry.youtubeVideoId}</span>
                        )}
                      </Link>
                    ) : entry.entityLabel ? (
                      <span>{entry.entityLabel}</span>
                    ) : (
                      <span className={styles.none}>—</span>
                    )}
                  </td>
                  <td className={`${styles.numCol} ${styles.unitsBadge} ${entry.units >= 50 ? styles.unitsHigh : ''}`}>
                    {entry.units}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ── Page ─────────────────────────────────────────────────────────────────────

export default function QuotaHistoryPage() {
  const [days, setDays] = useState(7);

  const { data, isLoading, isError } = useQuery({
    queryKey: ['quotaHistory', days],
    queryFn: () => fetchQuotaHistory(days),
    refetchInterval: 60_000,
  });

  const summary = data ? groupByOperation(data.items) : [];
  const groups = data ? groupByActionId(data.items) : [];
  const limit = 9_000;
  const pct = data ? Math.round((data.totalUnits / limit) * 100) : 0;

  return (
    <div className={styles.container}>
      <header className={styles.header}>
        <div>
          <span className={styles.eyebrow}>Logging</span>
          <h1>Quota History</h1>
        </div>
        <div className={styles.headerRight}>
          <select
            className={`${f.input} ${styles.daySelect}`}
            value={days}
            onChange={(e) => setDays(Number(e.target.value))}
          >
            {DAYS_OPTIONS.map((o) => (
              <option key={o.value} value={o.value}>{o.label}</option>
            ))}
          </select>
        </div>
      </header>

      {/* Summary cards */}
      {data && (
        <div className={styles.summaryRow}>
          <div className={`panel ${styles.summaryCard}`}>
            <div className={styles.summaryValue}>{data.totalUnits.toLocaleString()}</div>
            <div className={styles.summaryLabel}>Total units used</div>
            <div className={styles.quotaBar}>
              <div
                className={`${styles.quotaFill} ${pct > 70 ? styles.quotaFillWarn : ''} ${pct > 90 ? styles.quotaFillError : ''}`}
                style={{ width: `${Math.min(pct, 100)}%` }}
              />
            </div>
            <div className={styles.summaryMeta}>{pct}% of 9,000 daily limit</div>
          </div>
          <div className={`panel ${styles.summaryCard}`}>
            <div className={styles.summaryValue}>{groups.length.toLocaleString()}</div>
            <div className={styles.summaryLabel}>Actions</div>
            <div className={styles.summaryMeta}>{data.items.length} API calls total</div>
          </div>
          {summary[0] && (
            <div className={`panel ${styles.summaryCard}`}>
              <div className={styles.summaryValue}>{summary[0].units.toLocaleString()}</div>
              <div className={styles.summaryLabel}>Highest cost: {operationLabel(summary[0].op)}</div>
              <div className={styles.summaryMeta}>{summary[0].count} calls × {OPERATION_COST[summary[0].op] ?? '?'} units</div>
            </div>
          )}
        </div>
      )}

      {/* Breakdown by operation */}
      {summary.length > 0 && (
        <section className="panel">
          <h2 className={styles.sectionTitle}>
            <BarChart2 size={15} />
            Usage by operation
          </h2>
          <table className={styles.breakdownTable}>
            <thead>
              <tr>
                <th>Operation</th>
                <th className={styles.numCol}>Calls</th>
                <th className={styles.numCol}>Units each</th>
                <th className={styles.numCol}>Total units</th>
                <th className={styles.barCol}></th>
              </tr>
            </thead>
            <tbody>
              {summary.map(({ op, count, units }) => (
                <tr key={op} className={styles.breakdownRow}>
                  <td>
                    <span className={styles.opLabel}>{operationLabel(op)}</span>
                    <span className={styles.opCode}>{op}</span>
                  </td>
                  <td className={styles.numCol}>{count.toLocaleString()}</td>
                  <td className={styles.numCol}>{OPERATION_COST[op] ?? '?'}</td>
                  <td className={styles.numCol}><strong>{units.toLocaleString()}</strong></td>
                  <td className={styles.barCol}>
                    <div className={styles.miniBarTrack}>
                      <div
                        className={styles.miniBarFill}
                        style={{ width: `${Math.round((units / data!.totalUnits) * 100)}%` }}
                      />
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </section>
      )}

      {/* Action groups */}
      <section>
        <h2 className={styles.sectionTitle} style={{ marginBottom: 'var(--space-3)' }}>
          Actions
          {data && <span className={styles.count}>{groups.length}</span>}
        </h2>

        {isLoading && (
          <div className={styles.state}>
            <Loader2 size={20} className={styles.spin} />
            <span>Loading quota history…</span>
          </div>
        )}
        {isError && (
          <div className={styles.state}>
            <AlertCircle size={18} />
            <span>Failed to load quota history.</span>
          </div>
        )}
        {data?.items.length === 0 && (
          <div className={styles.empty}>No quota usage recorded for this period.</div>
        )}

        {groups.length > 0 && (
          <div className={styles.groupList}>
            {groups.map((group, i) => (
              <ActionGroupRow key={i} group={group} />
            ))}
          </div>
        )}
      </section>
    </div>
  );
}
