'use client';

import { useState } from 'react';
import { useMutation, useQuery } from 'convex/react';
import { Bot } from 'lucide-react';
import { toast } from 'sonner';

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

type AgentSettings = {
  defaultBaseBranch?: string;
  runtime?: 'opencode' | 'openai_direct';
  agentModel: string;
  reasoningEffort: string;
  envFilePath?: string;
  customEnvFilePath?: string;
  materializeEnvFileByDefault?: boolean;
  aiProviderProfileId?: Id<'aiProviderProfiles'>;
};

export const AgentRequestForm = ({
  spoon,
  agentSettings,
}: {
  spoon: Doc<'spoons'>;
  agentSettings?: AgentSettings | null;
}) => {
  const secrets =
    useQuery(api.spoonSecrets.listForSpoon, {
      spoonId: spoon._id,
    }) ?? [];
  const profiles =
    useQuery(api.aiProviderProfiles.listMine, {})?.filter(
      (profile) => profile.enabled && profile.configured,
    ) ?? [];
  const defaultProfile = profiles.find((profile) => profile.isDefault);
  const createThread = useMutation(api.threads.createUserThread);
  const [prompt, setPrompt] = useState('');
  const [baseBranch, setBaseBranch] = useState(
    agentSettings?.defaultBaseBranch ??
      spoon.forkDefaultBranch ??
      spoon.upstreamDefaultBranch,
  );
  const [requestedBranchName, setRequestedBranchName] = useState('');
  const [materializeEnvFile, setMaterializeEnvFile] = useState(
    agentSettings?.materializeEnvFileByDefault ?? false,
  );
  const [envFilePath, setEnvFilePath] = useState(
    agentSettings?.envFilePath === 'custom'
      ? (agentSettings.customEnvFilePath ?? '.env.local')
      : (agentSettings?.envFilePath ?? '.env.local'),
  );
  const [aiProviderProfileId, setAiProviderProfileId] = useState(
    agentSettings?.aiProviderProfileId ?? '__settings',
  );
  const [submitting, setSubmitting] = useState(false);
  const effectiveProviderProfileId =
    aiProviderProfileId === '__settings'
      ? (agentSettings?.aiProviderProfileId ?? defaultProfile?._id)
      : aiProviderProfileId;
  const hasProvider = Boolean(
    effectiveProviderProfileId &&
    profiles.some((profile) => profile._id === effectiveProviderProfileId),
  );
  const selectedProfile = profiles.find((profile) =>
    aiProviderProfileId === '__settings'
      ? profile._id ===
        (agentSettings?.aiProviderProfileId ?? defaultProfile?._id)
      : profile._id === aiProviderProfileId,
  );

  const submit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setSubmitting(true);
    try {
      await createThread({
        spoonId: spoon._id,
        prompt,
        baseBranch,
        requestedBranchName: requestedBranchName || undefined,
        materializeEnvFile,
        envFilePath: materializeEnvFile ? envFilePath : undefined,
        aiProviderProfileId:
          aiProviderProfileId === '__settings'
            ? undefined
            : (aiProviderProfileId as Id<'aiProviderProfiles'>),
      });
      setPrompt('');
      setRequestedBranchName('');
      toast.success('Thread created.');
    } catch (error) {
      console.error(error);
      toast.error('Could not queue agent job.');
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Card className='shadow-none'>
      <CardHeader className='pb-3'>
        <CardTitle className='flex items-center gap-2 text-base'>
          <Bot className='size-4' />
          Request agent work
        </CardTitle>
      </CardHeader>
      <CardContent>
        <form onSubmit={submit} className='space-y-4'>
          <div className='grid gap-2'>
            <Label htmlFor='agentPrompt'>Prompt</Label>
            <Textarea
              id='agentPrompt'
              required
              minLength={12}
              value={prompt}
              placeholder='Update this fork to use Authentik as the sole Auth.js provider.'
              onChange={(event) => setPrompt(event.target.value)}
            />
          </div>
          <div className='grid gap-3 md:grid-cols-2'>
            <div className='grid gap-2'>
              <Label>Workspace runtime</Label>
              <Input value='OpenCode workspace' disabled />
            </div>
            <div className='grid gap-2'>
              <Label>AI provider</Label>
              <Select
                value={aiProviderProfileId}
                onValueChange={setAiProviderProfileId}
              >
                <SelectTrigger>
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value='__settings'>
                    Use default
                    {defaultProfile ? ` (${defaultProfile.name})` : ''}
                  </SelectItem>
                  {profiles.map((profile) => (
                    <SelectItem key={profile._id} value={profile._id}>
                      {profile.name} · {profile.provider.replaceAll('_', ' ')}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className='grid gap-2'>
              <Label htmlFor='baseBranch'>Base branch</Label>
              <Input
                id='baseBranch'
                value={baseBranch}
                onChange={(event) => setBaseBranch(event.target.value)}
              />
            </div>
            <div className='grid gap-2'>
              <Label htmlFor='workBranch'>Work branch</Label>
              <Input
                id='workBranch'
                value={requestedBranchName}
                placeholder='Auto-generated if blank'
                onChange={(event) => setRequestedBranchName(event.target.value)}
              />
            </div>
          </div>
          <div className='grid gap-3 md:grid-cols-[1fr_1fr]'>
            <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 {secrets.length} Spoon secret(s) are available as process
                  env. When enabled, Spoon also writes them to this file and
                  refuses to commit .env files.
                </p>
              </div>
              <Switch
                checked={materializeEnvFile}
                onCheckedChange={setMaterializeEnvFile}
              />
            </div>
            <div className='grid gap-2'>
              <Label htmlFor='envFilePath'>Env file path</Label>
              <Input
                id='envFilePath'
                value={envFilePath}
                disabled={!materializeEnvFile}
                onChange={(event) => setEnvFilePath(event.target.value)}
              />
            </div>
          </div>
          <div className='bg-muted/40 grid gap-1 rounded-md p-3 text-xs'>
            <span>
              Model:{' '}
              <strong>
                {selectedProfile?.defaultModel ?? 'Configure an AI provider'}
              </strong>
            </span>
            <span>
              Reasoning:{' '}
              <strong>{selectedProfile?.reasoningEffort ?? 'medium'}</strong>
            </span>
          </div>
          <Button type='submit' disabled={submitting || !hasProvider}>
            {submitting ? 'Creating...' : 'Create thread'}
          </Button>
        </form>
      </CardContent>
    </Card>
  );
};
