'use client';

import { useState } from 'react';
import Link from 'next/link';
import { useRouter, useSearchParams } from 'next/navigation';
import { DeleteThreadButton } from '@/components/threads/delete-thread-button';
import { useMutation, useQuery } from 'convex/react';
import { MessageSquare, Plus } from 'lucide-react';
import { toast } from 'sonner';

import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import { api } from '@spoon/backend/convex/_generated/api.js';
import {
  Badge,
  Button,
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Input,
  Label,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
  Switch,
  Textarea,
} from '@spoon/ui';

const formatTime = (value: number) => new Date(value).toLocaleString();

const ThreadsPage = () => {
  const router = useRouter();
  const params = useSearchParams();
  const source = params.get('source') ?? 'all';
  const status = params.get('status') ?? 'all';
  const [spoonFilter, setSpoonFilter] = useState('all');
  const [priorityFilter, setPriorityFilter] = useState('all');
  const [outcomeFilter, setOutcomeFilter] = useState('all');
  const [spoonId, setSpoonId] = useState('');
  const [title, setTitle] = useState('');
  const [prompt, setPrompt] = useState('');
  const [materializeEnvFile, setMaterializeEnvFile] = useState(false);
  const [envFilePath, setEnvFilePath] = useState('.env.local');
  const [creating, setCreating] = useState(false);
  const createThread = useMutation(api.threads.createUserThread);
  const spoons = useQuery(api.spoons.listMineWithState, {}) ?? [];
  const profiles = useQuery(api.aiProviderProfiles.listMine, {}) ?? [];
  const defaultProfile = profiles.find((profile) => profile.isDefault);
  const threads =
    useQuery(api.threads.listMine, {
      source: source as
        | 'all'
        | 'user_request'
        | 'upstream_update'
        | 'merge_conflict'
        | 'manual_review'
        | 'system',
      status: status as
        | 'all'
        | 'open'
        | 'queued'
        | 'running'
        | 'waiting_for_user'
        | 'changes_ready'
        | 'draft_pr_opened'
        | 'resolved'
        | 'ignored'
        | 'failed'
        | 'cancelled',
      limit: 100,
    }) ?? [];
  const visibleThreads = threads.filter((thread) => {
    if (spoonFilter !== 'all' && thread.spoonId !== spoonFilter) return false;
    if (priorityFilter !== 'all' && thread.priority !== priorityFilter) {
      return false;
    }
    if (
      outcomeFilter !== 'all' &&
      (thread.maintenanceOutcome ?? 'none') !== outcomeFilter
    ) {
      return false;
    }
    return true;
  });

  const updateFilter = (key: string, value: string) => {
    const next = new URLSearchParams(params.toString());
    if (value === 'all') next.delete(key);
    else next.set(key, value);
    router.push(next.size ? `/threads?${next.toString()}` : '/threads');
  };

  const threadTarget = (thread: (typeof visibleThreads)[number]) =>
    `/threads/${thread._id}`;
  const canDeleteThread = (thread: (typeof visibleThreads)[number]) => {
    const latestJobStatus = thread.latestJobStatus;
    const latestWorkspaceStatus = thread.latestJobWorkspaceStatus;
    if (!latestJobStatus && !latestWorkspaceStatus) return true;
    return (
      ['failed', 'cancelled', 'timed_out', 'draft_pr_opened'].includes(
        latestJobStatus ?? '',
      ) ||
      ['stopped', 'expired', 'failed'].includes(latestWorkspaceStatus ?? '')
    );
  };

  const submitThread = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (!spoonId || !prompt.trim()) return;
    setCreating(true);
    try {
      const threadId = await createThread({
        spoonId: spoonId as Id<'spoons'>,
        title: title.trim() || undefined,
        prompt,
        materializeEnvFile,
        envFilePath,
      });
      toast.success('Thread created.');
      router.push(`/threads/${threadId}`);
    } catch (error) {
      console.error(error);
      toast.error('Could not create thread.');
    } finally {
      setCreating(false);
    }
  };

  return (
    <main className='space-y-6'>
      <div className='flex flex-col justify-between gap-4 md:flex-row md:items-end'>
        <div>
          <h1 className='text-3xl font-semibold tracking-normal'>Threads</h1>
          <p className='text-muted-foreground mt-2'>
            Maintenance reviews, upstream decisions, and user-requested fork
            work across all Spoons.
          </p>
        </div>
        <Button asChild>
          <a href='#new-thread'>
            <Plus className='size-4' />
            New thread
          </a>
        </Button>
      </div>

      <Card id='new-thread' className='shadow-none'>
        <CardHeader>
          <CardTitle className='text-base'>New thread</CardTitle>
        </CardHeader>
        <CardContent>
          <form onSubmit={submitThread} className='grid gap-4 lg:grid-cols-2'>
            <div className='grid gap-2'>
              <Label>Spoon</Label>
              <Select value={spoonId} onValueChange={setSpoonId}>
                <SelectTrigger>
                  <SelectValue placeholder='Choose a Spoon' />
                </SelectTrigger>
                <SelectContent>
                  {spoons.map((spoon) => (
                    <SelectItem key={spoon._id} value={spoon._id}>
                      {spoon.name} · {spoon.upstreamOwner}/{spoon.upstreamRepo}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className='grid gap-2'>
              <Label>Title</Label>
              <Input
                value={title}
                placeholder='Optional'
                onChange={(event) => setTitle(event.target.value)}
              />
            </div>
            <div className='grid gap-2 lg:col-span-2'>
              <Label>Prompt</Label>
              <Textarea
                value={prompt}
                placeholder='Describe the change, review, or maintenance task.'
                required
                minLength={4}
                onChange={(event) => setPrompt(event.target.value)}
              />
            </div>
            <div className='flex items-center justify-between gap-4 rounded-md border p-3'>
              <div>
                <Label>Write Spoon secrets to env file</Label>
                <p className='text-muted-foreground text-xs'>
                  All Spoon secrets are always available as process env.
                </p>
              </div>
              <Switch
                checked={materializeEnvFile}
                onCheckedChange={setMaterializeEnvFile}
              />
            </div>
            <div className='grid gap-2'>
              <Label>Env file path</Label>
              <Input
                value={envFilePath}
                onChange={(event) => setEnvFilePath(event.target.value)}
              />
            </div>
            <div className='text-muted-foreground text-sm lg:col-span-2'>
              Provider:{' '}
              <span className='text-foreground font-medium'>
                {defaultProfile
                  ? `${defaultProfile.name} · ${defaultProfile.defaultModel}`
                  : 'Configure an AI provider in Settings'}
              </span>
            </div>
            <div className='lg:col-span-2'>
              <Button
                type='submit'
                disabled={
                  creating || !spoonId || !prompt.trim() || !defaultProfile
                }
              >
                {creating ? 'Creating...' : 'Create thread'}
              </Button>
            </div>
          </form>
        </CardContent>
      </Card>

      <div className='grid gap-3 md:grid-cols-2 xl:grid-cols-5'>
        <Select
          value={source}
          onValueChange={(value) => updateFilter('source', value)}
        >
          <SelectTrigger className='w-full md:w-56'>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value='all'>All sources</SelectItem>
            <SelectItem value='user_request'>User requests</SelectItem>
            <SelectItem value='upstream_update'>Upstream updates</SelectItem>
            <SelectItem value='merge_conflict'>Merge conflicts</SelectItem>
            <SelectItem value='manual_review'>Manual review</SelectItem>
            <SelectItem value='system'>System</SelectItem>
          </SelectContent>
        </Select>
        <Select
          value={status}
          onValueChange={(value) => updateFilter('status', value)}
        >
          <SelectTrigger>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value='all'>All statuses</SelectItem>
            <SelectItem value='open'>Open</SelectItem>
            <SelectItem value='queued'>Queued</SelectItem>
            <SelectItem value='running'>Running</SelectItem>
            <SelectItem value='waiting_for_user'>Waiting</SelectItem>
            <SelectItem value='changes_ready'>Changes ready</SelectItem>
            <SelectItem value='draft_pr_opened'>Draft PR opened</SelectItem>
            <SelectItem value='resolved'>Resolved</SelectItem>
            <SelectItem value='ignored'>Ignored</SelectItem>
            <SelectItem value='failed'>Failed</SelectItem>
            <SelectItem value='cancelled'>Cancelled</SelectItem>
          </SelectContent>
        </Select>
        <Select value={spoonFilter} onValueChange={setSpoonFilter}>
          <SelectTrigger>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value='all'>All Spoons</SelectItem>
            {spoons.map((spoon) => (
              <SelectItem key={spoon._id} value={spoon._id}>
                {spoon.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
        <Select value={priorityFilter} onValueChange={setPriorityFilter}>
          <SelectTrigger>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value='all'>All priorities</SelectItem>
            <SelectItem value='low'>Low</SelectItem>
            <SelectItem value='normal'>Normal</SelectItem>
            <SelectItem value='high'>High</SelectItem>
          </SelectContent>
        </Select>
        <Select value={outcomeFilter} onValueChange={setOutcomeFilter}>
          <SelectTrigger>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value='all'>All outcomes</SelectItem>
            <SelectItem value='none'>No outcome</SelectItem>
            <SelectItem value='auto_synced'>Auto synced</SelectItem>
            <SelectItem value='sync_recommended'>Sync recommended</SelectItem>
            <SelectItem value='ignored'>Ignored</SelectItem>
            <SelectItem value='review_pr_recommended'>Review PR</SelectItem>
            <SelectItem value='manual_review_required'>
              Manual review
            </SelectItem>
            <SelectItem value='conflict_resolution_required'>
              Conflict
            </SelectItem>
            <SelectItem value='failed'>Failed</SelectItem>
            <SelectItem value='unknown'>Unknown</SelectItem>
          </SelectContent>
        </Select>
      </div>

      <div className='space-y-3'>
        {visibleThreads.length ? (
          visibleThreads.map((thread) => (
            <Card
              key={thread._id}
              role='link'
              tabIndex={0}
              className='hover:border-primary/50 cursor-pointer shadow-none transition-colors'
              onClick={() => router.push(threadTarget(thread))}
              onKeyDown={(event) => {
                if (event.key === 'Enter' || event.key === ' ') {
                  event.preventDefault();
                  router.push(threadTarget(thread));
                }
              }}
            >
              <CardContent className='grid gap-3 p-4 md:grid-cols-[1fr_auto] md:items-center'>
                <div className='min-w-0'>
                  <div className='flex flex-wrap items-center gap-2'>
                    <h2 className='truncate font-medium'>{thread.title}</h2>
                    {thread.spoonName ? (
                      <Badge variant='outline'>{thread.spoonName}</Badge>
                    ) : null}
                    <Badge variant='outline'>
                      {thread.source.replaceAll('_', ' ')}
                    </Badge>
                    <Badge>{thread.status.replaceAll('_', ' ')}</Badge>
                    {thread.maintenanceOutcome ? (
                      <Badge variant='secondary'>
                        {thread.maintenanceOutcome.replaceAll('_', ' ')}
                      </Badge>
                    ) : null}
                  </div>
                  <p className='text-muted-foreground mt-1 line-clamp-2 text-sm'>
                    {thread.summary ??
                      'No summary has been recorded for this thread yet.'}
                  </p>
                </div>
                <div className='text-muted-foreground text-xs md:text-right'>
                  <p>{formatTime(thread.updatedAt)}</p>
                  <p className='capitalize'>{thread.priority} priority</p>
                  {thread.latestJobStatus ? (
                    <p>{thread.latestJobStatus.replaceAll('_', ' ')}</p>
                  ) : null}
                  {thread.latestJobWorkspaceStatus ? (
                    <p>
                      Workspace:{' '}
                      {thread.latestJobWorkspaceStatus.replaceAll('_', ' ')}
                    </p>
                  ) : null}
                  <div className='mt-2 flex justify-start gap-2 md:justify-end'>
                    {thread.latestAgentJobId ? (
                      <Button size='sm' variant='outline' asChild>
                        <Link
                          href={threadTarget(thread)}
                          onClick={(event) => event.stopPropagation()}
                        >
                          Open workspace
                        </Link>
                      </Button>
                    ) : null}
                    {thread.latestJobPullRequestUrl ? (
                      <Button size='sm' asChild>
                        <a
                          href={thread.latestJobPullRequestUrl}
                          target='_blank'
                          rel='noreferrer'
                          onClick={(event) => event.stopPropagation()}
                        >
                          PR
                        </a>
                      </Button>
                    ) : null}
                    <DeleteThreadButton
                      threadId={thread._id as Id<'threads'>}
                      disabled={!canDeleteThread(thread)}
                      label='Delete'
                    />
                  </div>
                </div>
              </CardContent>
            </Card>
          ))
        ) : (
          <Card className='shadow-none'>
            <CardContent className='text-muted-foreground flex items-center gap-3 p-6 text-sm'>
              <MessageSquare className='size-4' />
              Threads appear when you ask Spoon to change a fork or when
              upstream changes need review.
            </CardContent>
          </Card>
        )}
      </div>
    </main>
  );
};

export default ThreadsPage;
