import { useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  ArrowDown,
  ArrowUp,
  Eye,
  EyeOff,
  History,
  Plus,
  RefreshCw,
  Search,
  UserMinus,
  X,
} from "lucide-react";
import { api, HttpError, type ManagedChannel, type Tag } from "../lib/api";
import { formatEta } from "../lib/format";
import { notify } from "../lib/notifications";
import Tooltip from "./Tooltip";
import Avatar from "./Avatar";

export type ChannelStatusFilter = "all" | "needs_full" | "fully_synced" | "hidden";

const STATUS_FILTERS: { id: ChannelStatusFilter; labelKey: string }[] = [
  { id: "all", labelKey: "channels.filters.all" },
  { id: "needs_full", labelKey: "channels.filters.needsFull" },
  { id: "fully_synced", labelKey: "channels.filters.fullySynced" },
  { id: "hidden", labelKey: "channels.filters.hidden" },
];

export default function Channels({
  canWrite,
  onViewChannel,
  statusFilter,
  setStatusFilter,
  onOpenWizard,
}: {
  canWrite: boolean;
  onViewChannel: (id: string, name: string) => void;
  statusFilter: ChannelStatusFilter;
  setStatusFilter: (f: ChannelStatusFilter) => void;
  onOpenWizard: () => void;
}) {
  const { t } = useTranslation();
  const qc = useQueryClient();

  // A YouTube-gated action (sync, backfill, unsubscribe) that 403s means the user hasn't
  // granted the needed scope — surface that with a "Connect" action instead of a vague fail.
  const notifyActionError = (err: unknown, fallbackKey: string) => {
    if (err instanceof HttpError && err.status === 403) {
      notify({
        level: "error",
        message: t("channels.notify.needYouTube"),
        action: { label: t("channels.notify.connect"), onClick: onOpenWizard },
      });
    } else {
      notify({ level: "error", message: t(fallbackKey) });
    }
  };
  const channelsQuery = useQuery({ queryKey: ["channels"], queryFn: api.channels });
  const tagsQuery = useQuery({ queryKey: ["tags"], queryFn: api.tags });
  const statusQuery = useQuery({ queryKey: ["my-status"], queryFn: api.myStatus });
  const [q, setQ] = useState("");
  const [newTag, setNewTag] = useState("");

  const invalidate = () => {
    qc.invalidateQueries({ queryKey: ["channels"] });
    qc.invalidateQueries({ queryKey: ["tags"] });
    qc.invalidateQueries({ queryKey: ["my-status"] });
  };

  const userTags = (tagsQuery.data ?? []).filter((t) => !t.system);

  const patch = useMutation({
    mutationFn: (v: {
      id: string;
      body: { priority?: number; hidden?: boolean; deep_requested?: boolean };
    }) => api.updateChannel(v.id, v.body),
    // Requesting full history may have just pulled in a channel's recent uploads, so
    // refresh the per-user status and feed too — not only the channel list.
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ["channels"] });
      qc.invalidateQueries({ queryKey: ["my-status"] });
      qc.invalidateQueries({ queryKey: ["feed"] });
      qc.invalidateQueries({ queryKey: ["feed-count"] });
    },
  });
  // Priority is updated optimistically in place and NOT re-sorted/refetched, so the list
  // doesn't jump (the server list is priority-sorted; refetching would reorder rows and
  // lose your scroll position). The new order takes effect next time the page loads.
  const bumpPriority = (id: string, current: number, delta: number) => {
    const next = current + delta;
    qc.setQueryData<ManagedChannel[]>(["channels"], (old) =>
      (old ?? []).map((ch) => (ch.id === id ? { ...ch, priority: next } : ch))
    );
    api
      .updateChannel(id, { priority: next })
      .catch(() => qc.invalidateQueries({ queryKey: ["channels"] }));
  };

  const attach = useMutation({
    mutationFn: (v: { id: string; tagId: number }) => api.attachChannelTag(v.id, v.tagId),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["channels"] }),
  });
  const detach = useMutation({
    mutationFn: (v: { id: string; tagId: number }) => api.detachChannelTag(v.id, v.tagId),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["channels"] }),
  });
  const syncSubs = useMutation({
    mutationFn: () => api.syncSubscriptions(),
    onSuccess: (r: { subscriptions?: number }) => {
      invalidate();
      notify({ level: "success", message: t("channels.notify.synced", { count: r.subscriptions ?? 0 }) });
    },
    onError: (e) => notifyActionError(e, "channels.notify.syncFailed"),
  });
  const createTag = useMutation({
    mutationFn: (name: string) => api.createTag({ name, category: "other" }),
    onSuccess: () => {
      setNewTag("");
      qc.invalidateQueries({ queryKey: ["tags"] });
    },
  });
  const deleteTag = useMutation({
    mutationFn: (id: number) => api.deleteTag(id),
    onSuccess: () => invalidate(),
  });
  const unsubscribe = useMutation({
    mutationFn: (id: string) => api.unsubscribeChannel(id),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ["channels"] });
      qc.invalidateQueries({ queryKey: ["my-status"] });
      notify({ level: "success", message: t("channels.notify.unsubscribed") });
    },
    onError: (e) => notifyActionError(e, "channels.notify.unsubscribeFailed"),
  });
  const deepAll = useMutation({
    mutationFn: () => api.deepAll(true),
    onSuccess: (r: { updated?: number }) => {
      qc.invalidateQueries({ queryKey: ["channels"] });
      qc.invalidateQueries({ queryKey: ["my-status"] });
      notify({
        level: "success",
        message: t("channels.notify.fullHistoryRequested", { count: r.updated ?? 0 }),
      });
    },
    onError: (e) => notifyActionError(e, "channels.notify.fullHistoryFailed"),
  });

  const channels = (channelsQuery.data ?? [])
    .filter((c) => !q || (c.title ?? "").toLowerCase().includes(q.toLowerCase()))
    .filter((c) =>
      statusFilter === "needs_full"
        ? !c.backfill_done
        : statusFilter === "fully_synced"
          ? c.backfill_done
          : statusFilter === "hidden"
            ? c.hidden
            : true
    );
  const s = statusQuery.data;

  return (
    <div className="p-4 max-w-4xl mx-auto">
      {/* Per-user sync status */}
      {s && (
        <div className="flex flex-wrap items-center gap-x-5 gap-y-1 text-sm text-muted mb-4">
          <Stat label={t("channels.stats.channels")} value={s.channels_total} hint={t("channels.stats.channelsHint")} />
          <Stat
            label={t("channels.stats.recentSynced")}
            value={`${s.channels_recent_synced}/${s.channels_total}`}
            hint={t("channels.stats.recentSyncedHint")}
          />
          <Stat
            label={t("channels.stats.fullHistory")}
            value={`${s.channels_deep_done}/${s.channels_deep_requested}`}
            hint={t("channels.stats.fullHistoryHint")}
          />
          {s.deep_pending_count > 0 && (
            <Stat
              label={t("channels.stats.left")}
              value={formatEta(s.deep_eta_seconds)}
              hint={t("channels.stats.leftHint", { count: s.deep_pending_count })}
            />
          )}
          <Stat label={t("channels.stats.myVideos")} value={s.my_videos.toLocaleString()} hint={t("channels.stats.myVideosHint")} />
          <Stat
            label={t("channels.stats.quotaLeft")}
            value={s.quota_remaining_today.toLocaleString()}
            hint={t("channels.stats.quotaLeftHint")}
          />
        </div>
      )}

      {/* Toolbar */}
      <div className="flex items-center gap-2 mb-4">
        <div className="relative flex-1">
          <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted" />
          <input
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder={t("channels.filterPlaceholder")}
            className="w-full bg-card border border-border rounded-full pl-9 pr-4 py-2 text-sm outline-none focus:border-accent"
          />
        </div>
        <Tooltip
          side="bottom"
          hint={t("channels.syncSubscriptionsHint")}
        >
          <button
            onClick={() => syncSubs.mutate()}
            disabled={syncSubs.isPending}
            className="glass-card glass-hover flex items-center gap-2 px-3 py-2 rounded-xl text-sm disabled:opacity-50 transition"
          >
            <RefreshCw className={`w-4 h-4 ${syncSubs.isPending ? "animate-spin" : ""}`} />
            {t("channels.syncSubscriptions")}
          </button>
        </Tooltip>
        <Tooltip
          side="bottom"
          hint={t("channels.backfillEverythingHint")}
        >
          <button
            onClick={() => deepAll.mutate()}
            disabled={deepAll.isPending}
            className="glass-card glass-hover flex items-center gap-2 px-3 py-2 rounded-xl text-sm disabled:opacity-50 transition"
          >
            <History className={`w-4 h-4 ${deepAll.isPending ? "animate-pulse" : ""}`} />
            {t("channels.backfillEverything")}
          </button>
        </Tooltip>
      </div>

      {/* Status filter */}
      <div className="flex flex-wrap items-center gap-1.5 mb-4">
        {STATUS_FILTERS.map((f) => (
          <button
            key={f.id}
            onClick={() => setStatusFilter(f.id)}
            className={`text-xs px-2.5 py-1 rounded-full border transition ${
              statusFilter === f.id
                ? "bg-accent text-accent-fg border-accent"
                : "bg-card border-border text-muted hover:border-accent"
            }`}
          >
            {t(f.labelKey)}
          </button>
        ))}
      </div>

      <p className="text-xs text-muted mb-4 leading-relaxed">
        <Trans
          i18nKey="channels.intro"
          components={[
            <b className="text-fg/80" />,
            <b className="text-fg/80" />,
            <b className="text-fg/80" />,
          ]}
        />
      </p>

      {/* Your tags */}
      <div className="flex flex-wrap items-center gap-1.5 mb-4">
        <Tooltip hint={t("channels.tags.yourTagsHint")}>
          <span className="text-xs uppercase tracking-wide text-muted mr-1 cursor-help underline decoration-dotted decoration-muted/40 underline-offset-4">
            {t("channels.tags.yourTags")}
          </span>
        </Tooltip>
        {userTags.map((t) => (
          <span
            key={t.id}
            className="inline-flex items-center gap-1 text-xs px-2 py-1 rounded-full bg-card border border-border"
          >
            {t.name}
            <button onClick={() => deleteTag.mutate(t.id)} className="text-muted hover:text-red-400">
              <X className="w-3 h-3" />
            </button>
          </span>
        ))}
        <form
          onSubmit={(e) => {
            e.preventDefault();
            if (newTag.trim()) createTag.mutate(newTag.trim());
          }}
          className="inline-flex items-center gap-1"
        >
          <input
            value={newTag}
            onChange={(e) => setNewTag(e.target.value)}
            placeholder={t("channels.tags.newTag")}
            className="w-24 bg-card border border-border rounded-full px-2.5 py-1 text-xs outline-none focus:border-accent"
          />
          <button type="submit" className="text-muted hover:text-accent" title={t("channels.tags.createTag")}>
            <Plus className="w-4 h-4" />
          </button>
        </form>
      </div>

      {/* Channel list */}
      {channelsQuery.isLoading ? (
        <div className="text-muted py-8">{t("channels.loading")}</div>
      ) : channels.length === 0 ? (
        <div className="text-muted py-8">{t("channels.empty")}</div>
      ) : (
        <div className="flex flex-col gap-1.5">
          {channels.map((c) => (
            <ChannelRow
              key={c.id}
              c={c}
              userTags={userTags}
              canWrite={canWrite}
              onUnsubscribe={() => {
                if (
                  window.confirm(
                    t("channels.confirmUnsubscribe", { name: c.title ?? c.id })
                  )
                )
                  unsubscribe.mutate(c.id);
              }}
              onView={() => onViewChannel(c.id, c.title ?? t("channels.row.thisChannel"))}
              onPriority={(d) => bumpPriority(c.id, c.priority, d)}
              onHide={() => patch.mutate({ id: c.id, body: { hidden: !c.hidden } })}
              onDeep={() =>
                patch.mutate({ id: c.id, body: { deep_requested: !c.deep_requested } })
              }
              onToggleTag={(tagId) =>
                c.tag_ids.includes(tagId)
                  ? detach.mutate({ id: c.id, tagId })
                  : attach.mutate({ id: c.id, tagId })
              }
            />
          ))}
        </div>
      )}
    </div>
  );
}

function Stat({
  label,
  value,
  hint,
}: {
  label: string;
  value: string | number;
  hint?: string;
}) {
  return (
    <Tooltip hint={hint ?? ""}>
      <span className={hint ? "cursor-help" : ""}>
        <span className="text-fg font-semibold">{value}</span> {label}
      </span>
    </Tooltip>
  );
}

function SyncBadge({ ok, label, hint }: { ok: boolean; label: string; hint?: string }) {
  return (
    <Tooltip hint={hint ?? ""}>
      <span
        className={`text-[10px] px-1.5 py-0.5 rounded-full border ${
          ok ? "border-accent/40 text-accent" : "border-border text-muted"
        }`}
      >
        {label}
      </span>
    </Tooltip>
  );
}

function ChannelRow({
  c,
  userTags,
  canWrite,
  onUnsubscribe,
  onView,
  onPriority,
  onHide,
  onDeep,
  onToggleTag,
}: {
  c: ManagedChannel;
  userTags: Tag[];
  canWrite: boolean;
  onUnsubscribe: () => void;
  onView: () => void;
  onPriority: (delta: number) => void;
  onHide: () => void;
  onDeep: () => void;
  onToggleTag: (tagId: number) => void;
}) {
  const { t } = useTranslation();
  return (
    <div
      className={`glass-card glass-hover flex items-center gap-3 p-2.5 rounded-xl transition ${
        c.hidden ? "opacity-60" : ""
      }`}
    >
      <Tooltip hint={t("channels.row.priorityHint")}>
        <div className="flex flex-col items-center cursor-help">
          <button onClick={() => onPriority(1)} className="text-muted hover:text-accent" aria-label={t("channels.row.raisePriority")}>
            <ArrowUp className="w-3.5 h-3.5" />
          </button>
          <span className="text-xs text-muted tabular-nums">{c.priority}</span>
          <button onClick={() => onPriority(-1)} className="text-muted hover:text-accent" aria-label={t("channels.row.lowerPriority")}>
            <ArrowDown className="w-3.5 h-3.5" />
          </button>
        </div>
      </Tooltip>

      <Avatar
        src={c.thumbnail_url}
        fallback={c.title ?? ""}
        className="w-10 h-10 rounded-full shrink-0"
      />

      <div className="min-w-0 flex-1">
        <button onClick={onView} className="text-sm font-semibold truncate hover:text-accent block max-w-full text-left">
          {c.title ?? c.id}
        </button>
        <div className="flex items-center gap-2 text-[11px] text-muted">
          <span>{t("channels.row.stored", { count: c.stored_videos, formatted: c.stored_videos.toLocaleString() })}</span>
          {c.subscriber_count != null && <span>· {t("channels.row.subs", { count: c.subscriber_count, formatted: c.subscriber_count.toLocaleString() })}</span>}
        </div>
        <div className="flex flex-wrap items-center gap-1 mt-1">
          <SyncBadge
            ok={c.recent_synced}
            label={t("channels.row.recent")}
            hint={c.recent_synced ? t("channels.row.recentSyncedHint") : t("channels.row.recentNotSyncedHint")}
          />
          {c.backfill_done ? (
            <SyncBadge ok label={t("channels.row.full")} hint={t("channels.row.fullHint")} />
          ) : c.deep_requested ? (
            <Tooltip hint={t("channels.row.queuedRequestedHint")}>
              <button
                onClick={onDeep}
                className="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded-full border border-accent bg-accent text-accent-fg transition"
              >
                <History className="w-3 h-3" />
                {t("channels.row.fullHistoryQueued")}
              </button>
            </Tooltip>
          ) : c.deep_in_queue ? (
            <Tooltip hint={t("channels.row.queuedByOtherHint")}>
              <span className="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded-full border border-accent/40 text-accent">
                <History className="w-3 h-3" />
                {t("channels.row.fullHistoryComing")}
              </span>
            </Tooltip>
          ) : (
            <Tooltip hint={t("channels.row.getFullHistoryHint")}>
              <button
                onClick={onDeep}
                className="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded-full border bg-card border-border text-muted hover:border-accent transition"
              >
                <History className="w-3 h-3" />
                {t("channels.row.getFullHistory")}
              </button>
            </Tooltip>
          )}
          {userTags.map((t) => {
            const on = c.tag_ids.includes(t.id);
            return (
              <button
                key={t.id}
                onClick={() => onToggleTag(t.id)}
                className={`text-[10px] px-1.5 py-0.5 rounded-full border transition ${
                  on
                    ? "bg-accent text-accent-fg border-accent"
                    : "bg-card border-border text-muted hover:border-accent"
                }`}
              >
                {t.name}
              </button>
            );
          })}
        </div>
      </div>

      <Tooltip
        hint={c.hidden ? t("channels.row.hiddenHint") : t("channels.row.hideHint")}
      >
        <button onClick={onHide} className="text-muted hover:text-fg shrink-0" aria-label={c.hidden ? t("channels.row.unhide") : t("channels.row.hideFromFeed")}>
          {c.hidden ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
        </button>
      </Tooltip>

      {canWrite && (
        <Tooltip hint={t("channels.row.unsubscribeHint")}>
          <button
            onClick={onUnsubscribe}
            className="text-muted hover:text-red-400 shrink-0"
            aria-label={t("channels.row.unsubscribeOnYoutube")}
          >
            <UserMinus className="w-4 h-4" />
          </button>
        </Tooltip>
      )}
    </div>
  );
}
