'use client';

import React, { useEffect, useState } from 'react';
import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar';
import { AppSidebar } from '@/components/app-sidebar';
import { Badge } from '@/components/ui/badge';
import { SiteHeader } from '@/components/site-header';
import { useRouter } from 'next/navigation';
import { toast } from 'sonner';
import { Progress } from '@/components/ui/progress';
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import {
  Field,
  FieldGroup,
  FieldLabel,
  FieldDescription,
} from '@/components/ui/field';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Trash2Icon, Edit, Check, X } from 'lucide-react';
import { Switch } from '@/components/ui/switch';
import { getVideoDuration } from '@/utils/getVideoDuration';

type Course = { id: string; title: string; code?: string };
type Playlist = { id: string; title: string; courseId: string };
type Video = {
  id: string;
  title: string;
  durationSec?: number;
  thumbnail?: string;
  url: string;
  index: number;
  locked: boolean;
  instantAccess: boolean;
  playlistId: string;
  playlist: {
    id: string;
    title: string;
    course: {
      id: string;
      title: string;
    };
  };
  restrictedCourseIds?: string[];
};

function VideosUI() {
  const router = useRouter();
  const [courses, setCourses] = useState<Course[]>([]);
  const [playlists, setPlaylists] = useState<Playlist[]>([]);
  const [videos, setVideos] = useState<Video[]>([]);
  const [loading, setLoading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState<number | null>(null);

  // form state
  const [videoTitle, setVideoTitle] = useState('');
  const [videoFile, setVideoFile] = useState<File | null>(null);
  const [videoPlaylistId, setVideoPlaylistId] = useState('');
  const [thumbFile, setThumbFile] = useState<File | null>(null);
  const [videoDurationSec, setVideoDurationSec] = useState<number | null>(null);
  const [deletingId, setDeletingId] = useState<string | null>(null);
  const [togglingId, setTogglingId] = useState<string | null>(null);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [editingTitle, setEditingTitle] = useState('');
  const [savingEditId, setSavingEditId] = useState<string | null>(null);
  
  // Manual file copy mode
  const [useManualFileCopy, setUseManualFileCopy] = useState(false);
  const [pendingVideoId, setPendingVideoId] = useState<string | null>(null);
  const [finalizingVideoId, setFinalizingVideoId] = useState<string | null>(null);

  useEffect(() => {
    fetchData();
  }, []);

  async function toggleInstantAccess(videoId: string, currentValue: boolean) {
    setTogglingId(videoId);
    try {
      const res = await fetch(`/api/admin/videos/${videoId}/instant-access`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ instantAccess: !currentValue }),
      });

      if (res.ok) {
        const data = await res.json();
        // Update the video in state
        setVideos((prev) =>
          prev.map((v) =>
            v.id === videoId ? { ...v, instantAccess: data.video.instantAccess } : v
          )
        );
        toast.success(`Video ${!currentValue ? 'set to' : 'removed from'} instant access`);
      } else {
        toast.error('Failed to toggle instant access');
      }
    } catch (err) {
      console.error('Error toggling instant access:', err);
      toast.error('Error toggling instant access');
    } finally {
      setTogglingId(null);
    }
  }

  async function toggleLocked(videoId: string, currentValue: boolean) {
    setTogglingId(videoId);
    try {
      const res = await fetch(`/api/admin/videos/${videoId}/locked`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ locked: !currentValue }),
      });

      if (res.ok) {
        const data = await res.json();
        // Update the video in state
        setVideos((prev) =>
          prev.map((v) =>
            v.id === videoId ? { ...v, locked: data.video.locked } : v
          )
        );
        toast.success(`Video ${!currentValue ? 'locked' : 'unlocked'}`);
      } else {
        toast.error('Failed to toggle lock status');
      }
    } catch (err) {
      console.error('Error toggling locked:', err);
      toast.error('Error toggling lock status');
    } finally {
      setTogglingId(null);
    }
  }

  async function fetchData() {
    try {
      const [metaRes, videosRes] = await Promise.all([
        fetch('/api/admin/meta'),
        fetch('/api/admin/videos'),
      ]);

      if (metaRes.ok) {
        const json = await metaRes.json();
        setCourses(json.courses || []);
        setPlaylists(json.playlists || []);
        if (!videoPlaylistId && json.playlists?.[0]) {
          setVideoPlaylistId(json.playlists[0].id);
        }
      }

      if (videosRes.ok) {
        const json = await videosRes.json();
        // Ensure data is serialized properly
        setVideos(json.map((v: any) => ({
          id: v.id,
          title: v.title,
          durationSec: v.durationSec,
          thumbnail: v.thumbnail,
          url: v.url,
          index: v.index,
          locked: v.locked,
          instantAccess: v.instantAccess,
          playlistId: v.playlistId,
          playlist: {
            id: v.playlist.id,
            title: v.playlist.title,
            course: {
              id: v.playlist.course.id,
              title: v.playlist.course.title,
            },
          },
          restrictedCourseIds: (v.videoCourses ?? [])
            .filter((assignment: any) => assignment.exclusive)
            .map((assignment: any) => assignment.courseId),
        })));
      }
    } catch (err) {
      console.error('Failed to fetch data', err);
      toast.error('Failed to fetch data');
    }
  }

  async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const f = e.target.files?.[0] ?? null;
    setVideoFile(f);
    setVideoDurationSec(null);
    if (!f) return;
    try {
      const secs = await getVideoDuration(f);
      setVideoDurationSec(secs);
      toast.success(`Duration: ${secs}s`);
    } catch (err) {
      console.warn('duration read failed', err);
      toast.error('Could not read duration (server will measure)');
    }
  }

  async function uploadVideo(e: React.FormEvent) {
    e.preventDefault();
    if (!videoPlaylistId) {
      toast.error('Select a playlist');
      return;
    }

    // Manual file copy mode
    if (useManualFileCopy) {
      if (!videoFile) {
        toast.error('Select a file to get the filename');
        return;
      }
      // Create video entry without uploading the actual file
      setLoading(true);
      try {
        const form = new FormData();
        form.append('title', videoTitle);
        form.append('playlistId', videoPlaylistId);
        form.append('manualFileCopy', 'true'); // Flag to skip file upload
        if (videoDurationSec) form.append('durationSec', String(videoDurationSec));
        if (thumbFile) form.append('thumbnail', thumbFile);

        const res = await fetch('/api/admin/upload', {
          method: 'POST',
          body: form,
        });

        const data = await res.json();

        if (!res.ok) {
          toast.error(data.error ?? 'Upload failed');
          return;
        }

        // Show modal with the video ID
        setPendingVideoId(data.video.id);
        toast.success(`Video created! Copy file as: ${data.video.id}.mp4`);
      } catch (err: any) {
        console.error('upload error', err);
        toast.error(String(err?.message ?? 'Upload failed'));
      } finally {
        setLoading(false);
      }
      return;
    }

    // Normal upload mode
    if (!videoFile) {
      toast.error('Pick a file first');
      return;
    }

    setLoading(true);
    setUploadProgress(0);

    try {
      const form = new FormData();
      form.append('file', videoFile);
      form.append('title', videoTitle);
      form.append('playlistId', videoPlaylistId);
      if (videoDurationSec) form.append('durationSec', String(videoDurationSec));
      if (thumbFile) form.append('thumbnail', thumbFile);

      await new Promise<void>((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('POST', '/api/admin/upload');

        xhr.upload.onprogress = (ev) => {
          if (ev.lengthComputable) {
            const pct = Math.round((ev.loaded / ev.total) * 100);
            setUploadProgress(pct);
          }
        };

        xhr.onload = async () => {
          let body: any = null;
          try {
            body = xhr.responseText ? JSON.parse(xhr.responseText) : null;
          } catch (err) {
            body = { error: xhr.responseText };
          }

          if (xhr.status >= 200 && xhr.status < 300) {
            toast.success('Upload complete');
            setUploadProgress(null);
            setVideoFile(null);
            setVideoTitle('');
            setVideoDurationSec(null);
            setThumbFile(null);
            await fetchData();
            router.refresh();
            resolve();
          } else {
            const errMsg = body?.error ?? `Upload failed (${xhr.status})`;
            toast.error(errMsg);
            setUploadProgress(null);
            reject(new Error(errMsg));
          }
        };

        xhr.onerror = () => {
          toast.error('Upload failed (network)');
          setUploadProgress(null);
          reject(new Error('network error'));
        };

        // Timeout for 2GB uploads over Tailscale: 50 minutes
        xhr.timeout = 50 * 60 * 1000;
        xhr.ontimeout = () => {
          toast.error('Upload timed out');
          setUploadProgress(null);
          reject(new Error('timeout'));
        };

        xhr.send(form);
      });
    } catch (err: any) {
      console.error('upload error', err);
      if (!uploadProgress) setUploadProgress(null);
      toast.error(String(err?.message ?? 'Upload failed'));
    } finally {
      setLoading(false);
    }
  }

  async function finalizeManualUpload(videoId: string) {
    setFinalizingVideoId(videoId);
    try {
      const res = await fetch('/api/admin/upload/finalize', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ videoId }),
      });

      const data = await res.json();

      if (!res.ok) {
        toast.error(data.error ?? 'Finalization failed');
        return;
      }

      toast.success(`Video finalized! ${data.message}`);
      setPendingVideoId(null);
      setVideoFile(null);
      setVideoTitle('');
      setVideoDurationSec(null);
      setThumbFile(null);
      setUseManualFileCopy(false);
      await fetchData();
      router.refresh();
    } catch (err: any) {
      console.error('finalize error', err);
      toast.error(String(err?.message ?? 'Finalization failed'));
    } finally {
      setFinalizingVideoId(null);
    }
  }

  async function deleteVideo(videoId: string) {
    setDeletingId(videoId);
    try {
      const res = await fetch(`/api/admin/delete-video`, {
        method: 'DELETE',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ videoId }),
      });
      if (res.ok) {
        toast.success('Video deleted');
        await fetchData();
        router.refresh();
      } else {
        const txt = await res.text();
        toast.error('Failed to delete video: ' + txt);
      }
    } catch (err: any) {
      toast.error('Error: ' + String(err.message ?? err));
    } finally {
      setDeletingId(null);
    }
  }

  async function updateVideoTitle(videoId: string, newTitle: string) {
    if (!newTitle.trim()) {
      toast.error('Title cannot be empty');
      return;
    }

    setSavingEditId(videoId);
    try {
      const res = await fetch(`/api/admin/update-video`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ videoId, title: newTitle }),
      });
      if (res.ok) {
        toast.success('Video updated');
        setEditingId(null);
        setEditingTitle('');
        await fetchData();
        router.refresh();
      } else {
        const txt = await res.text();
        toast.error('Failed to update video: ' + txt);
      }
    } catch (err: any) {
      toast.error('Error: ' + String(err.message ?? err));
    } finally {
      setSavingEditId(null);
    }
  }

  return (
    <div className="flex flex-col gap-6 py-4 md:gap-6 md:py-6 px-4 lg:px-16">
      <Card>
        <CardHeader>
          <CardTitle>Upload Video</CardTitle>
        </CardHeader>
        <CardContent>
          <form onSubmit={uploadVideo}>
            <FieldGroup>
              <Field>
                <FieldLabel htmlFor="videoTitle">Video title</FieldLabel>
                <FieldDescription>Title shown in the playlist.</FieldDescription>
                <Input
                  id="videoTitle"
                  required
                  value={videoTitle}
                  onChange={(e) => setVideoTitle(e.target.value)}
                  placeholder="e.g. Lesson 1 — Intro to the Rig"
                />
              </Field>

              <Field>
                <div className="flex items-center gap-3">
                  <Switch
                    id="manualFileCopy"
                    checked={useManualFileCopy}
                    onCheckedChange={setUseManualFileCopy}
                  />
                  <label htmlFor="manualFileCopy" className="text-sm cursor-pointer">
                    Manual file copy mode
                  </label>
                </div>
                <FieldDescription>
                  {useManualFileCopy
                    ? 'Creates DB entry and thumbnail. You will copy the file manually to the server.'
                    : 'Upload file directly from browser.'}
                </FieldDescription>
              </Field>

              <Field>
                <FieldLabel htmlFor="videoPlaylist">Playlist</FieldLabel>
                <FieldDescription>
                  Select which playlist this video belongs to.
                </FieldDescription>

                <Select
                  value={videoPlaylistId}
                  onValueChange={(val) => setVideoPlaylistId(val)}
                >
                  <SelectTrigger aria-label="Choose playlist">
                    <SelectValue placeholder="Select playlist" />
                  </SelectTrigger>
                  <SelectContent>
                    {playlists.map((p) => (
                      <SelectItem key={p.id} value={p.id}>
                        {p.title}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </Field>

              <Field>
                <FieldLabel htmlFor="videoFile">Video file</FieldLabel>
                <FieldDescription>
                  {useManualFileCopy
                    ? 'Select the file to get its name, then copy manually to: /uploads/videos/{videoId}.mp4'
                    : 'Large files will be uploaded to the server.'}
                </FieldDescription>
                <div className="grid w-full max-w-sm items-center gap-3">
                  <Input
                    id="videoFile"
                    type="file"
                    accept="video/*"
                    onChange={handleFileChange}
                    className="block w-full text-sm"
                    required={!useManualFileCopy}
                  />
                  {videoDurationSec ? (
                    <div className="text-sm text-muted-foreground">
                      Duration: {videoDurationSec}s
                    </div>
                  ) : null}

                  {uploadProgress !== null && !useManualFileCopy ? (
                    <div className="w-full">
                      <div className="flex items-center justify-between mb-1">
                        <div className="text-sm">Uploading</div>
                        <div className="text-xs text-muted-foreground">
                          {uploadProgress}%
                        </div>
                      </div>
                      <Progress value={uploadProgress} />
                    </div>
                  ) : null}
                </div>
              </Field>
              <Field>
                <FieldLabel htmlFor="thumbFile">Thumbnail</FieldLabel>
                <div className="grid w-full max-w-sm items-center gap-3">
                  <Input
                    id="thumbFile"
                    type="file"
                    accept="image/*"
                    onChange={(e) => setThumbFile(e.target.files?.[0] ?? null)}
                    className="block w-full text-sm"
                  />

                  {thumbFile ? (
                    <img
                      src={URL.createObjectURL(thumbFile)}
                      className="w-32 h-20 rounded object-cover border mt-2"
                    />
                  ) : null}
                </div>
              </Field>

              <Field>
                <Button
                  type="submit"
                  disabled={loading || (!useManualFileCopy && !videoFile) || !videoPlaylistId}
                >
                  {loading
                    ? useManualFileCopy
                      ? 'Creating…'
                      : 'Uploading…'
                    : useManualFileCopy
                    ? 'Create & Setup Manual Copy'
                    : 'Upload video'}
                </Button>
              </Field>
            </FieldGroup>
          </form>
        </CardContent>
      </Card>

      {/* Manual file copy modal */}
      {pendingVideoId && (
        <Card className="border-blue-200 bg-blue-50">
          <CardHeader>
            <CardTitle className="text-blue-900">File Ready for Manual Copy</CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="bg-white p-4 rounded border border-blue-200">
              <p className="text-sm text-muted-foreground mb-2">
                Copy your video file to the following location on your server:
              </p>
              <code className="block bg-muted p-3 rounded text-sm font-mono mb-2">
                /uploads/videos/{pendingVideoId}.mp4
              </code>
              <p className="text-sm text-muted-foreground">
                The file must be named exactly as shown above (using the video ID).
              </p>
            </div>

            <Button
              onClick={() => finalizeManualUpload(pendingVideoId)}
              disabled={finalizingVideoId !== null}
              className="w-full"
            >
              {finalizingVideoId ? 'Checking file…' : 'I have placed the file'}
            </Button>
            <Button
              variant="outline"
              onClick={() => setPendingVideoId(null)}
              disabled={finalizingVideoId !== null}
              className="w-full"
            >
              Cancel
            </Button>
          </CardContent>
        </Card>
      )}

      <Card>
        <CardHeader>
          <CardTitle>Videos</CardTitle>
        </CardHeader>
        <CardContent>
          {videos.length === 0 ? (
            <div className="text-center py-8 text-muted-foreground">
              No videos yet
            </div>
          ) : (
            <div className="overflow-x-auto">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>Thumbnail</TableHead>
                    <TableHead>Title</TableHead>
                    <TableHead>Playlist</TableHead>
                    <TableHead>Course</TableHead>
                    <TableHead className="text-center">Locked</TableHead>
                    <TableHead className="text-center">Instant Access</TableHead>
                    <TableHead className="text-right">Actions</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {videos.map((video) => (
                    <TableRow key={video.id}>
                      <TableCell>
                        {video.thumbnail ? (
                          <img
                            src={video.thumbnail}
                            alt={video.title}
                            className="w-16 h-9 object-cover rounded text-xs"
                          />
                        ) : (
                          <div className="w-16 h-9 bg-muted rounded flex items-center justify-center">
                            <span className="text-xs text-muted-foreground">
                              No image
                            </span>
                          </div>
                        )}
                      </TableCell>
                      <TableCell className="font-medium max-w-xs">
                        {editingId === video.id ? (
                          <div className="flex gap-2 items-center">
                            <Input
                              value={editingTitle}
                              onChange={(e) => setEditingTitle(e.target.value)}
                              className="h-8"
                              autoFocus
                              onKeyDown={(e) => {
                                if (e.key === 'Enter') {
                                  updateVideoTitle(video.id, editingTitle);
                                }
                                if (e.key === 'Escape') {
                                  setEditingId(null);
                                  setEditingTitle('');
                                }
                              }}
                            />
                            <Button
                              variant="ghost"
                              size="sm"
                              onClick={() => updateVideoTitle(video.id, editingTitle)}
                              disabled={savingEditId === video.id}
                            >
                              <Check className="w-4 h-4" />
                            </Button>
                            <Button
                              variant="ghost"
                              size="sm"
                              onClick={() => {
                                setEditingId(null);
                                setEditingTitle('');
                              }}
                              disabled={savingEditId === video.id}
                            >
                              <X className="w-4 h-4" />
                            </Button>
                          </div>
                        ) : (
                          <div className="flex flex-col gap-1">
                            <div className="flex gap-2 items-center">
                              <span className="truncate">{video.title}</span>
                              <Button
                                variant="ghost"
                                size="sm"
                                onClick={() => {
                                  setEditingId(video.id);
                                  setEditingTitle(video.title);
                                }}
                              >
                                <Edit className="w-4 h-4" />
                              </Button>
                            </div>
                            {video.restrictedCourseIds?.length ? (
                              <div className="flex flex-wrap gap-1">
                                {video.restrictedCourseIds.map((courseId) => {
                                  const course = courses.find((c) => c.id === courseId);
                                  const label = course?.code ?? course?.title ?? 'Course';
                                  return (
                                    <Badge
                                      key={`${video.id}-${courseId}`}
                                      variant="secondary"
                                    >
                                      {label}
                                    </Badge>
                                  );
                                })}
                              </div>
                            ) : null}
                          </div>
                        )}
                      </TableCell>
                      <TableCell>{video.playlist.title}</TableCell>
                      <TableCell>{video.playlist.course.title}</TableCell>
                      <TableCell className="text-center">
                        <Switch
                          checked={video.locked}
                          onCheckedChange={() => toggleLocked(video.id, video.locked)}
                          disabled={togglingId === video.id}
                          aria-label="Toggle lock status"
                        />
                      </TableCell>
                      <TableCell className="text-center">
                        <Switch
                          checked={video.instantAccess}
                          onCheckedChange={() => toggleInstantAccess(video.id, video.instantAccess)}
                          disabled={togglingId === video.id}
                          aria-label="Toggle instant access"
                        />
                      </TableCell>
                      <TableCell className="text-right">
                        <div className="flex gap-1 justify-end">
                          <Button
                            variant="ghost"
                            size="sm"
                            onClick={() => router.push(`/admin/videos/${video.id}/edit`)}
                          >
                            <Edit className="w-4 h-4" />
                          </Button>
                          <AlertDialog>
                            <AlertDialogTrigger asChild>
                              <Button
                                variant="ghost"
                                size="sm"
                                disabled={deletingId === video.id}
                              >
                                <Trash2Icon className="w-4 h-4" />
                              </Button>
                            </AlertDialogTrigger>
                            <AlertDialogContent>
                              <AlertDialogHeader>
                                <AlertDialogTitle>Delete Video</AlertDialogTitle>
                                <AlertDialogDescription>
                                  Are you sure you want to delete "{video.title}"?
                                </AlertDialogDescription>
                              </AlertDialogHeader>
                              <div className="flex gap-2 justify-end">
                                <AlertDialogCancel>Cancel</AlertDialogCancel>
                                <AlertDialogAction
                                  onClick={() => deleteVideo(video.id)}
                                >
                                  Delete
                                </AlertDialogAction>
                              </div>
                            </AlertDialogContent>
                          </AlertDialog>
                        </div>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
}

export default function VideosAdminClient() {
  return (
    <SidebarProvider
      style={
        {
          '--sidebar-width': 'calc(var(--spacing) * 72)',
          '--header-height': 'calc(var(--spacing) * 12)',
        } as React.CSSProperties
      }
    >
      <AppSidebar variant="inset" />
      <SidebarInset>
        <SiteHeader />
        <div className="flex flex-1 flex-col">
          <div className="@container/main flex flex-1 flex-col gap-2">
            <VideosUI />
          </div>
        </div>
      </SidebarInset>
    </SidebarProvider>
  );
}
