'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,
} from '@spoon/ui';

const efforts = ['minimal', 'low', 'medium', 'high', 'xhigh'] as const;
type AgentSettings = {
  enabled: boolean;
  runtime?: 'opencode' | 'openai_direct';
  defaultBaseBranch?: string;
  branchPrefix: string;
  installCommand?: string;
  checkCommand?: string;
  testCommand?: string;
  agentModel: string;
  reasoningEffort: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
  envFilePath?: string;
  customEnvFilePath?: string;
  materializeEnvFileByDefault?: boolean;
  autoDetectCommands?: boolean;
  allowUserFileEditing?: boolean;
  aiProviderProfileId?: Id<'aiProviderProfiles'>;
};

export const SpoonAgentSettingsForm = ({
  spoon,
  settings,
}: {
  spoon: Doc<'spoons'>;
  settings?: AgentSettings | null;
}) => {
  const update = useMutation(api.spoonAgentSettings.update);
  const profiles = useQuery(api.aiProviderProfiles.listMine, {}) ?? [];
  const modelCatalog = useQuery(api.aiProviderModels.listAvailableForUser);
  const configuredProfiles = profiles.filter(
    (profile) => profile.enabled && profile.configured,
  );
  const defaultProfile = configuredProfiles.find(
    (profile) => profile.isDefault,
  );
  const [enabled, setEnabled] = useState(settings?.enabled ?? true);
  const [defaultBaseBranch, setDefaultBaseBranch] = useState(
    settings?.defaultBaseBranch ??
      spoon.forkDefaultBranch ??
      spoon.upstreamDefaultBranch,
  );
  const [branchPrefix, setBranchPrefix] = useState(
    settings?.branchPrefix ?? 'spoon/agent',
  );
  const [installCommand, setInstallCommand] = useState(
    settings?.installCommand ?? '',
  );
  const [checkCommand, setCheckCommand] = useState(
    settings?.checkCommand ?? '',
  );
  const [testCommand, setTestCommand] = useState(settings?.testCommand ?? '');
  const [envFilePath, setEnvFilePath] = useState(
    settings?.envFilePath ?? '.env.local',
  );
  const [customEnvFilePath, setCustomEnvFilePath] = useState(
    settings?.customEnvFilePath ?? '',
  );
  const [materializeEnvFileByDefault, setMaterializeEnvFileByDefault] =
    useState(settings?.materializeEnvFileByDefault ?? false);
  const [autoDetectCommands, setAutoDetectCommands] = useState(
    settings?.autoDetectCommands ?? true,
  );
  const [allowUserFileEditing, setAllowUserFileEditing] = useState(
    settings?.allowUserFileEditing ?? true,
  );
  const [aiProviderProfileId, setAiProviderProfileId] = useState(
    settings?.aiProviderProfileId ?? '__default',
  );
  const selectedProfile = profiles.find(
    (profile) =>
      profile._id ===
      (aiProviderProfileId === '__default'
        ? defaultProfile?._id
        : aiProviderProfileId),
  );
  const selectedModelProfile = modelCatalog?.profiles.find(
    (profile) =>
      profile.profileId ===
      (aiProviderProfileId === '__default'
        ? defaultProfile?._id
        : aiProviderProfileId),
  );
  const [agentModel, setAgentModel] = useState(
    settings?.aiProviderProfileId ? settings.agentModel : '',
  );
  const [reasoningEffort, setReasoningEffort] = useState<
    'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
  >(
    !settings?.aiProviderProfileId
      ? 'medium'
      : settings.reasoningEffort === 'none'
        ? 'minimal'
        : settings.reasoningEffort,
  );

  const selectableModels = selectedModelProfile?.configured
    ? selectedModelProfile.models
    : [];
  const selectedAgentModel =
    agentModel && selectableModels.some((model) => model.id === agentModel)
      ? agentModel
      : selectableModels.some(
            (model) => model.id === selectedModelProfile?.defaultModel,
          )
        ? (selectedModelProfile?.defaultModel ?? '')
        : (selectableModels[0]?.id ?? '');

  const save = async () => {
    try {
      await update({
        spoonId: spoon._id,
        enabled,
        runtime: 'opencode',
        defaultBaseBranch,
        branchPrefix,
        installCommand: installCommand || undefined,
        checkCommand: checkCommand || undefined,
        testCommand: testCommand || undefined,
        agentModel: selectedAgentModel || undefined,
        reasoningEffort,
        envFilePath: envFilePath as
          | '.env'
          | '.env.local'
          | '.env.production'
          | '.env.production.local'
          | 'custom',
        customEnvFilePath: customEnvFilePath || undefined,
        materializeEnvFileByDefault,
        autoDetectCommands,
        allowUserFileEditing,
        aiProviderProfileId:
          aiProviderProfileId === '__default'
            ? undefined
            : (aiProviderProfileId as Id<'aiProviderProfiles'>),
        clearAiProviderProfile: aiProviderProfileId === '__default',
      });
      toast.success('Agent settings saved.');
    } catch (error) {
      console.error(error);
      toast.error('Could not save agent settings.');
    }
  };

  return (
    <Card className='shadow-none'>
      <CardHeader>
        <CardTitle className='flex items-center gap-2 text-base'>
          <Bot className='size-4' />
          Agent runtime
        </CardTitle>
      </CardHeader>
      <CardContent className='space-y-4'>
        <div className='flex items-center justify-between gap-4'>
          <Label htmlFor='agentEnabled'>Enable agent jobs</Label>
          <Switch
            id='agentEnabled'
            checked={enabled}
            onCheckedChange={setEnabled}
          />
        </div>
        <div className='grid gap-3 md:grid-cols-2'>
          <div className='grid gap-2'>
            <Label>Runtime</Label>
            <Input value='OpenCode workspace' disabled />
          </div>
          <div className='grid gap-2'>
            <Label>AI provider profile</Label>
            <Select
              value={aiProviderProfileId}
              onValueChange={(value) => {
                setAiProviderProfileId(value);
                const nextProfile = profiles.find(
                  (profile) =>
                    profile._id ===
                    (value === '__default' ? defaultProfile?._id : value),
                );
                if (!nextProfile?.configured) setAgentModel('');
                if (nextProfile?.configured) {
                  setReasoningEffort(
                    nextProfile.reasoningEffort === 'none'
                      ? 'minimal'
                      : nextProfile.reasoningEffort,
                  );
                }
              }}
            >
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value='__default'>
                  Use account default
                  {defaultProfile ? ` (${defaultProfile.name})` : ''}
                </SelectItem>
                {configuredProfiles.map((profile) => (
                  <SelectItem key={profile._id} value={profile._id}>
                    {profile.name} · {profile.provider.replaceAll('_', ' ')}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <p className='text-muted-foreground text-xs'>
              Workspaces use this profile. Use default resolves to your account
              default provider.
            </p>
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='defaultBaseBranch'>Default base branch</Label>
            <Input
              id='defaultBaseBranch'
              value={defaultBaseBranch}
              onChange={(event) => setDefaultBaseBranch(event.target.value)}
            />
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='branchPrefix'>Branch prefix</Label>
            <Input
              id='branchPrefix'
              value={branchPrefix}
              onChange={(event) => setBranchPrefix(event.target.value)}
            />
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='agentModel'>Model</Label>
            <Select
              value={selectedAgentModel}
              onValueChange={setAgentModel}
              disabled={!selectableModels.length}
            >
              <SelectTrigger id='agentModel'>
                <SelectValue placeholder='Choose a configured model' />
              </SelectTrigger>
              <SelectContent>
                {selectableModels.map((option) => (
                  <SelectItem key={option.id} value={option.id}>
                    {option.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            {!selectableModels.length ? (
              <p className='text-muted-foreground text-xs'>
                Configure an enabled AI provider profile with saved model
                options in Settings before choosing a model.
              </p>
            ) : null}
          </div>
          <div className='grid gap-2'>
            <Label>Reasoning effort</Label>
            <Select
              value={reasoningEffort}
              onValueChange={(value) =>
                setReasoningEffort(
                  value as 'minimal' | 'low' | 'medium' | 'high' | 'xhigh',
                )
              }
            >
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {efforts.map((effort) => (
                  <SelectItem key={effort} value={effort}>
                    {effort}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='installCommand'>Install command</Label>
            <Input
              id='installCommand'
              value={installCommand}
              placeholder='Auto-detect from lockfile'
              onChange={(event) => setInstallCommand(event.target.value)}
            />
            <p className='text-muted-foreground text-xs'>
              Leave blank to inspect the repository and choose bun, pnpm, yarn,
              or npm.
            </p>
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='checkCommand'>Check command</Label>
            <Input
              id='checkCommand'
              value={checkCommand}
              placeholder='Auto-detect typecheck or lint'
              onChange={(event) => setCheckCommand(event.target.value)}
            />
            <p className='text-muted-foreground text-xs'>
              Leave blank to read package.json scripts after cloning.
            </p>
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='testCommand'>Test command</Label>
            <Input
              id='testCommand'
              value={testCommand}
              placeholder='Auto-detect test script'
              onChange={(event) => setTestCommand(event.target.value)}
            />
            <p className='text-muted-foreground text-xs'>
              Leave blank to run the detected test script when one exists.
            </p>
          </div>
          <div className='grid gap-2'>
            <Label>Env file path</Label>
            <Select value={envFilePath} onValueChange={setEnvFilePath}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value='.env'>.env</SelectItem>
                <SelectItem value='.env.local'>.env.local</SelectItem>
                <SelectItem value='.env.production'>.env.production</SelectItem>
                <SelectItem value='.env.production.local'>
                  .env.production.local
                </SelectItem>
                <SelectItem value='custom'>Custom path</SelectItem>
              </SelectContent>
            </Select>
          </div>
          {envFilePath === 'custom' ? (
            <div className='grid gap-2'>
              <Label htmlFor='customEnvFilePath'>Custom env path</Label>
              <Input
                id='customEnvFilePath'
                value={customEnvFilePath}
                placeholder='.env.spoon'
                onChange={(event) => setCustomEnvFilePath(event.target.value)}
              />
            </div>
          ) : null}
          <div className='flex items-center justify-between gap-4 rounded-md border p-3'>
            <div>
              <Label>Materialize env file by default</Label>
              <p className='text-muted-foreground text-xs'>
                Write all Spoon secrets into the chosen .env file for new
                workspaces.
              </p>
            </div>
            <Switch
              checked={materializeEnvFileByDefault}
              onCheckedChange={setMaterializeEnvFileByDefault}
            />
          </div>
          <div className='flex items-center justify-between gap-4 rounded-md border p-3'>
            <div>
              <Label>Auto-detect commands</Label>
              <p className='text-muted-foreground text-xs'>
                Inspect package files after cloning.
              </p>
            </div>
            <Switch
              checked={autoDetectCommands}
              onCheckedChange={setAutoDetectCommands}
            />
          </div>
          <div className='flex items-center justify-between gap-4 rounded-md border p-3'>
            <div>
              <Label>Allow browser file editing</Label>
              <p className='text-muted-foreground text-xs'>
                Let users edit workspace files manually.
              </p>
            </div>
            <Switch
              checked={allowUserFileEditing}
              onCheckedChange={setAllowUserFileEditing}
            />
          </div>
        </div>
        <Button
          type='button'
          onClick={save}
          disabled={
            !selectedProfile?.configured ||
            !selectableModels.some((model) => model.id === selectedAgentModel)
          }
        >
          Save agent settings
        </Button>
      </CardContent>
    </Card>
  );
};
