"use client";

import { useState, useEffect } from "react";
import { Plus, Upload, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  useChannels,
  useCreateChannel,
  useUpdateChannel,
  useDeleteChannel,
  useGenerateSchedule,
} from "@/hooks/use-channels";
import { useAuthContext } from "@/context/auth-context";
import { api } from "@/lib/api";
import { toast } from "sonner";
import { useQueryClient } from "@tanstack/react-query";
import { ChannelCard } from "./components/channel-card";
import { CreateChannelDialog } from "./components/create-channel-dialog";
import { DeleteChannelDialog } from "./components/delete-channel-dialog";
import { EditChannelSheet } from "./components/edit-channel-sheet";
import { ScheduleSheet } from "./components/schedule-sheet";
import { ImportChannelDialog, type ChannelImportData } from "./components/import-channel-dialog";
import type { ChannelResponse, ProgrammingBlock, RecyclePolicy } from "@/lib/types";

export default function DashboardPage() {
  const { token } = useAuthContext();
  const queryClient = useQueryClient();
  const { data: channels, isLoading, error } = useChannels();

  const createChannel = useCreateChannel();
  const updateChannel = useUpdateChannel();
  const deleteChannel = useDeleteChannel();
  const generateSchedule = useGenerateSchedule();

  // Channel ordering — persisted to localStorage
  const [channelOrder, setChannelOrder] = useState<string[]>([]);
  useEffect(() => {
    try {
      const stored = localStorage.getItem("k-tv-channel-order");
      if (stored) setChannelOrder(JSON.parse(stored));
    } catch {}
  }, []);

  const saveOrder = (order: string[]) => {
    setChannelOrder(order);
    try { localStorage.setItem("k-tv-channel-order", JSON.stringify(order)); } catch {}
  };

  // Sort channels by stored order; new channels appear at the end
  const sortedChannels = channels
    ? [...channels].sort((a, b) => {
        const ai = channelOrder.indexOf(a.id);
        const bi = channelOrder.indexOf(b.id);
        if (ai === -1 && bi === -1) return 0;
        if (ai === -1) return 1;
        if (bi === -1) return -1;
        return ai - bi;
      })
    : [];

  const handleMoveUp = (channelId: string) => {
    const ids = sortedChannels.map((c) => c.id);
    const idx = ids.indexOf(channelId);
    if (idx <= 0) return;
    const next = [...ids];
    [next[idx - 1], next[idx]] = [next[idx], next[idx - 1]];
    saveOrder(next);
  };

  const handleMoveDown = (channelId: string) => {
    const ids = sortedChannels.map((c) => c.id);
    const idx = ids.indexOf(channelId);
    if (idx === -1 || idx >= ids.length - 1) return;
    const next = [...ids];
    [next[idx], next[idx + 1]] = [next[idx + 1], next[idx]];
    saveOrder(next);
  };

  // Regenerate all channels
  const [isRegeneratingAll, setIsRegeneratingAll] = useState(false);
  const handleRegenerateAll = async () => {
    if (!token || !channels || channels.length === 0) return;
    setIsRegeneratingAll(true);
    let failed = 0;
    for (const ch of channels) {
      try {
        await api.schedule.generate(ch.id, token);
        queryClient.invalidateQueries({ queryKey: ["schedule", ch.id] });
      } catch {
        failed++;
      }
    }
    setIsRegeneratingAll(false);
    if (failed === 0) toast.success(`All ${channels.length} schedules regenerated`);
    else toast.error(`${failed} schedule(s) failed to generate`);
  };

  const [createOpen, setCreateOpen] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [importPending, setImportPending] = useState(false);
  const [importError, setImportError] = useState<string | null>(null);
  const [editChannel, setEditChannel] = useState<ChannelResponse | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<ChannelResponse | null>(null);
  const [scheduleChannel, setScheduleChannel] = useState<ChannelResponse | null>(null);

  const handleCreate = (data: {
    name: string;
    timezone: string;
    description: string;
    access_mode?: import("@/lib/types").AccessMode;
    access_password?: string;
  }) => {
    createChannel.mutate(
      {
        name: data.name,
        timezone: data.timezone,
        description: data.description || undefined,
        access_mode: data.access_mode,
        access_password: data.access_password,
      },
      { onSuccess: () => setCreateOpen(false) },
    );
  };

  const handleEdit = (
    id: string,
    data: {
      name: string;
      description: string;
      timezone: string;
      schedule_config: { blocks: ProgrammingBlock[] };
      recycle_policy: RecyclePolicy;
      auto_schedule: boolean;
      access_mode?: import("@/lib/types").AccessMode;
      access_password?: string;
    },
  ) => {
    updateChannel.mutate(
      { id, data },
      { onSuccess: () => setEditChannel(null) },
    );
  };

  const handleImport = async (data: ChannelImportData) => {
    if (!token) return;
    setImportPending(true);
    setImportError(null);
    try {
      const created = await api.channels.create(
        { name: data.name, timezone: data.timezone, description: data.description },
        token,
      );
      await api.channels.update(
        created.id,
        { schedule_config: { blocks: data.blocks }, recycle_policy: data.recycle_policy },
        token,
      );
      await queryClient.invalidateQueries({ queryKey: ["channels"] });
      setImportOpen(false);
    } catch (e) {
      setImportError(e instanceof Error ? e.message : "Import failed");
    } finally {
      setImportPending(false);
    }
  };

  const handleExport = (channel: ChannelResponse) => {
    const payload = {
      name: channel.name,
      description: channel.description ?? undefined,
      timezone: channel.timezone,
      blocks: channel.schedule_config.blocks,
      recycle_policy: channel.recycle_policy,
    };
    const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `${channel.name.toLowerCase().replace(/\s+/g, "-")}.json`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const handleDelete = () => {
    if (!deleteTarget) return;
    deleteChannel.mutate(deleteTarget.id, {
      onSuccess: () => setDeleteTarget(null),
    });
  };

  return (
    <div className="mx-auto w-full max-w-5xl space-y-6 px-6 py-8">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-xl font-semibold text-zinc-100">My Channels</h1>
          <p className="mt-0.5 text-sm text-zinc-500">
            Build your broadcast lineup
          </p>
        </div>
        <div className="flex gap-2">
          {channels && channels.length > 0 && (
            <Button
              variant="outline"
              onClick={handleRegenerateAll}
              disabled={isRegeneratingAll}
              title="Regenerate schedules for all channels"
              className="border-zinc-700 text-zinc-400 hover:text-zinc-100"
            >
              <RefreshCw className={`size-4 ${isRegeneratingAll ? "animate-spin" : ""}`} />
              Regenerate all
            </Button>
          )}
          <Button variant="outline" onClick={() => setImportOpen(true)} className="border-zinc-700 text-zinc-300 hover:text-zinc-100">
            <Upload className="size-4" />
            Import
          </Button>
          <Button onClick={() => setCreateOpen(true)}>
            <Plus className="size-4" />
            New channel
          </Button>
        </div>
      </div>

      {/* Content */}
      {isLoading && (
        <div className="flex items-center justify-center py-20">
          <div className="h-5 w-5 animate-spin rounded-full border-2 border-zinc-700 border-t-zinc-300" />
        </div>
      )}

      {error && (
        <div className="rounded-lg border border-red-900/50 bg-red-950/20 px-4 py-3 text-sm text-red-400">
          {error.message}
        </div>
      )}

      {!isLoading && channels && channels.length === 0 && (
        <div className="flex flex-col items-center justify-center gap-3 rounded-xl border border-dashed border-zinc-800 py-20 text-center">
          <p className="text-sm text-zinc-500">No channels yet</p>
          <Button variant="outline" onClick={() => setCreateOpen(true)}>
            <Plus className="size-4" />
            Create your first channel
          </Button>
        </div>
      )}

      {sortedChannels.length > 0 && (
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {sortedChannels.map((channel, idx) => (
            <ChannelCard
              key={channel.id}
              channel={channel}
              isGenerating={
                generateSchedule.isPending &&
                generateSchedule.variables === channel.id
              }
              isFirst={idx === 0}
              isLast={idx === sortedChannels.length - 1}
              onEdit={() => setEditChannel(channel)}
              onDelete={() => setDeleteTarget(channel)}
              onGenerateSchedule={() => generateSchedule.mutate(channel.id)}
              onViewSchedule={() => setScheduleChannel(channel)}
              onExport={() => handleExport(channel)}
              onMoveUp={() => handleMoveUp(channel.id)}
              onMoveDown={() => handleMoveDown(channel.id)}
            />
          ))}
        </div>
      )}

      {/* Dialogs / sheets */}
      <ImportChannelDialog
        open={importOpen}
        onOpenChange={(open) => { if (!open) { setImportOpen(false); setImportError(null); } }}
        onSubmit={handleImport}
        isPending={importPending}
        error={importError}
      />

      <CreateChannelDialog
        open={createOpen}
        onOpenChange={setCreateOpen}
        onSubmit={handleCreate}
        isPending={createChannel.isPending}
        error={createChannel.error?.message}
      />

      <EditChannelSheet
        channel={editChannel}
        open={!!editChannel}
        onOpenChange={(open) => { if (!open) setEditChannel(null); }}
        onSubmit={handleEdit}
        isPending={updateChannel.isPending}
        error={updateChannel.error?.message}
      />

      <ScheduleSheet
        channel={scheduleChannel}
        open={!!scheduleChannel}
        onOpenChange={(open) => { if (!open) setScheduleChannel(null); }}
      />

      {deleteTarget && (
        <DeleteChannelDialog
          channelName={deleteTarget.name}
          open={!!deleteTarget}
          onOpenChange={(open) => { if (!open) setDeleteTarget(null); }}
          onConfirm={handleDelete}
          isPending={deleteChannel.isPending}
        />
      )}
    </div>
  );
}
