import { useState } from 'react';
import { Alert, Linking, Text, View } from 'react-native';
import { Stack, useRouter } from 'expo-router';
import { useAction, useMutation, useQuery } from 'convex/react';

import { api } from '@spoon/backend/convex/_generated/api.js';

import { AppScreen } from '~/components/ui/app-screen';
import { Badge } from '~/components/ui/badge';
import { Button } from '~/components/ui/button';
import { Card } from '~/components/ui/card';
import { Field } from '~/components/ui/field';
import { FormSection } from '~/components/ui/form-section';
import { PillTabs } from '~/components/ui/pill-tabs';
import { SheetSelect } from '~/components/ui/sheet-select';

type CreateMode = 'manual' | 'github';
type Provider = 'github' | 'gitea' | 'gitlab' | 'other';
type Visibility = 'public' | 'private' | 'internal' | 'unknown';
type MaintenanceMode = 'watch' | 'auto_pr' | 'paused';
type SyncCadence = 'daily' | 'weekly' | 'manual';
type ProductionRefStrategy =
  | 'default_branch'
  | 'latest_release'
  | 'tag_pattern';

type Repository = Awaited<
  ReturnType<
    ReturnType<
      typeof useAction<typeof api.githubNode.listInstallationRepositories>
    >
  >
>[number];

const NewSpoonRoute = () => {
  const router = useRouter();
  const createManual = useMutation(api.spoons.createManual);
  const syncInstallation = useAction(api.githubNode.syncConfiguredInstallation);
  const listRepositories = useAction(
    api.githubNode.listInstallationRepositories,
  );
  const installUrl = useQuery(api.github.getInstallUrl, {});
  const connection = useQuery(api.github.getConnection, {});
  const [mode, setMode] = useState<CreateMode>('manual');
  const [name, setName] = useState('');
  const [description, setDescription] = useState('');
  const [provider, setProvider] = useState<Provider>('github');
  const [upstreamOwner, setUpstreamOwner] = useState('');
  const [upstreamRepo, setUpstreamRepo] = useState('');
  const [upstreamDefaultBranch, setUpstreamDefaultBranch] = useState('main');
  const [upstreamUrl, setUpstreamUrl] = useState('');
  const [forkOwner, setForkOwner] = useState('');
  const [forkRepo, setForkRepo] = useState('');
  const [forkDefaultBranch, setForkDefaultBranch] = useState('main');
  const [forkUrl, setForkUrl] = useState('');
  const [visibility, setVisibility] = useState<Visibility>('unknown');
  const [maintenanceMode, setMaintenanceMode] =
    useState<MaintenanceMode>('watch');
  const [syncCadence, setSyncCadence] = useState<SyncCadence>('daily');
  const [productionRefStrategy, setProductionRefStrategy] =
    useState<ProductionRefStrategy>('default_branch');
  const [tagPattern, setTagPattern] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [loadingRepos, setLoadingRepos] = useState(false);
  const [repositories, setRepositories] = useState<Repository[]>([]);

  const submitManual = async () => {
    if (!name || !upstreamOwner || !upstreamRepo || !upstreamUrl) {
      Alert.alert('Missing fields', 'Name and upstream metadata are required.');
      return;
    }
    setSubmitting(true);
    try {
      const spoonId = await createManual({
        description: description || undefined,
        forkDefaultBranch: forkDefaultBranch || undefined,
        forkOwner: forkOwner || undefined,
        forkRepo: forkRepo || undefined,
        forkUrl: forkUrl || undefined,
        maintenanceMode,
        name,
        productionRefStrategy,
        provider,
        syncCadence,
        tagPattern: tagPattern || undefined,
        upstreamDefaultBranch,
        upstreamOwner,
        upstreamRepo,
        upstreamUrl,
        visibility,
      });
      router.replace(`/spoons/${spoonId}`);
    } catch (error) {
      console.error(error);
      Alert.alert('Could not create Spoon', 'Check the fields and try again.');
    } finally {
      setSubmitting(false);
    }
  };

  const loadRepos = async () => {
    setLoadingRepos(true);
    try {
      const result = await listRepositories({});
      setRepositories(result);
    } catch (error) {
      console.error(error);
      Alert.alert('Could not list repositories.');
    } finally {
      setLoadingRepos(false);
    }
  };

  const createFromRepo = async (repo: Repository) => {
    setSubmitting(true);
    try {
      const upstreamOwnerValue = upstreamOwner.trim() || repo.owner;
      const upstreamRepoValue = upstreamRepo.trim() || repo.name;
      const upstreamUrlValue = upstreamUrl.trim() || repo.url;
      const spoonId = await createManual({
        forkDefaultBranch: repo.defaultBranch,
        forkOwner: repo.owner,
        forkRepo: repo.name,
        forkUrl: repo.url,
        maintenanceMode: 'watch',
        name: repo.name,
        productionRefStrategy: 'default_branch',
        provider: 'github',
        syncCadence: 'daily',
        upstreamDefaultBranch: repo.defaultBranch,
        upstreamOwner: upstreamOwnerValue,
        upstreamRepo: upstreamRepoValue,
        upstreamUrl: upstreamUrlValue,
        visibility: repo.private ? 'private' : 'public',
      });
      router.replace(`/spoons/${spoonId}`);
    } catch (error) {
      console.error(error);
      Alert.alert('Could not create Spoon from repository.');
    } finally {
      setSubmitting(false);
    }
  };

  const confirmCreateFromRepo = (repo: Repository) => {
    const message = repo.fork
      ? 'GitHub did not provide parent repository metadata here. Add upstream fields above if you want Spoon to compare against the original project immediately.'
      : 'This will create a manual Spoon record using this repository as both upstream and fork unless you add upstream fields above.';

    Alert.alert('Create Spoon from repository metadata?', message, [
      { style: 'cancel', text: 'Cancel' },
      {
        onPress: () => void createFromRepo(repo),
        text: 'Create Spoon',
      },
    ]);
  };

  const syncGithub = async () => {
    setLoadingRepos(true);
    try {
      await syncInstallation({});
    } catch (error) {
      console.error(error);
      Alert.alert('Could not sync GitHub installation.');
    } finally {
      setLoadingRepos(false);
    }
  };

  return (
    <AppScreen>
      <Stack.Screen options={{ title: 'New Spoon' }} />
      <View>
        <Text className='text-foreground text-3xl font-bold'>New Spoon</Text>
        <Text className='text-muted-foreground mt-1'>
          Create a managed fork record manually or from GitHub.
        </Text>
      </View>
      <PillTabs
        tabs={[
          { label: 'Manual', value: 'manual' },
          { label: 'GitHub', value: 'github' },
        ]}
        value={mode}
        onChange={setMode}
      />

      {mode === 'manual' ? (
        <>
          <FormSection title='Basics'>
            <Field label='Spoon name' value={name} onChangeText={setName} />
            <Field
              label='Description'
              multiline
              value={description}
              onChangeText={setDescription}
            />
            <SheetSelect
              label='Git provider'
              options={[
                { label: 'GitHub', value: 'github' },
                { label: 'Gitea', value: 'gitea' },
                { label: 'GitLab', value: 'gitlab' },
                { label: 'Other', value: 'other' },
              ]}
              value={provider}
              onChange={setProvider}
            />
          </FormSection>
          <FormSection title='Upstream'>
            <Field
              label='Owner/org'
              value={upstreamOwner}
              onChangeText={setUpstreamOwner}
            />
            <Field
              label='Repository'
              value={upstreamRepo}
              onChangeText={setUpstreamRepo}
            />
            <Field
              label='Default branch'
              value={upstreamDefaultBranch}
              onChangeText={setUpstreamDefaultBranch}
            />
            <Field
              keyboardType='url'
              label='Upstream URL'
              value={upstreamUrl}
              onChangeText={setUpstreamUrl}
            />
          </FormSection>
          <FormSection title='Fork'>
            <Field
              label='Owner/org'
              value={forkOwner}
              onChangeText={setForkOwner}
            />
            <Field
              label='Repository'
              value={forkRepo}
              onChangeText={setForkRepo}
            />
            <Field
              label='Default branch'
              value={forkDefaultBranch}
              onChangeText={setForkDefaultBranch}
            />
            <Field
              keyboardType='url'
              label='Fork URL'
              value={forkUrl}
              onChangeText={setForkUrl}
            />
          </FormSection>
          <FormSection title='Maintenance'>
            <SheetSelect
              label='Visibility'
              options={[
                { label: 'Unknown', value: 'unknown' },
                { label: 'Public', value: 'public' },
                { label: 'Private', value: 'private' },
                { label: 'Internal', value: 'internal' },
              ]}
              value={visibility}
              onChange={setVisibility}
            />
            <SheetSelect
              label='Maintenance mode'
              options={[
                { label: 'Watch', value: 'watch' },
                { label: 'Auto PR', value: 'auto_pr' },
                { label: 'Paused', value: 'paused' },
              ]}
              value={maintenanceMode}
              onChange={setMaintenanceMode}
            />
            <SheetSelect
              label='Sync cadence'
              options={[
                { label: 'Daily', value: 'daily' },
                { label: 'Weekly', value: 'weekly' },
                { label: 'Manual', value: 'manual' },
              ]}
              value={syncCadence}
              onChange={setSyncCadence}
            />
            <SheetSelect
              label='Production ref'
              options={[
                { label: 'Default branch', value: 'default_branch' },
                { label: 'Latest release', value: 'latest_release' },
                { label: 'Tag pattern', value: 'tag_pattern' },
              ]}
              value={productionRefStrategy}
              onChange={setProductionRefStrategy}
            />
            {productionRefStrategy === 'tag_pattern' ? (
              <Field
                label='Tag pattern'
                value={tagPattern}
                onChangeText={setTagPattern}
              />
            ) : null}
          </FormSection>
          <Button disabled={submitting} onPress={() => void submitManual()}>
            {submitting ? 'Creating...' : 'Create Spoon'}
          </Button>
        </>
      ) : (
        <FormSection
          description='Repository listing is read from the GitHub App installation.'
          title='GitHub'
        >
          <View className='flex-row items-center justify-between'>
            <Text className='text-foreground font-medium'>Connection</Text>
            <Badge
              label={connection?.status ?? 'not connected'}
              tone={connection ? 'success' : 'warning'}
            />
          </View>
          {installUrl ? (
            <Button onPress={() => void Linking.openURL(installUrl)}>
              Install or manage GitHub App
            </Button>
          ) : null}
          <View className='flex-row gap-3'>
            <Button
              disabled={loadingRepos}
              variant='outline'
              onPress={() => void syncGithub()}
            >
              Sync
            </Button>
            <Button
              disabled={!connection || loadingRepos}
              onPress={() => void loadRepos()}
            >
              {loadingRepos ? 'Loading...' : 'Load repositories'}
            </Button>
          </View>
          <Text className='text-muted-foreground text-sm leading-5'>
            Optional upstream fields are used when the selected repository is a
            fork. If you leave them blank, Spoon tracks the selected repository
            as both upstream and fork until you correct it later.
          </Text>
          <Field
            label='Upstream owner/org'
            value={upstreamOwner}
            onChangeText={setUpstreamOwner}
          />
          <Field
            label='Upstream repository'
            value={upstreamRepo}
            onChangeText={setUpstreamRepo}
          />
          <Field
            keyboardType='url'
            label='Upstream URL'
            value={upstreamUrl}
            onChangeText={setUpstreamUrl}
          />
          {!loadingRepos && connection && repositories.length === 0 ? (
            <Card>
              <Text className='text-muted-foreground text-sm leading-5'>
                Load accessible repositories to create a Spoon from GitHub
                metadata.
              </Text>
            </Card>
          ) : null}
          {repositories.map((repo) => (
            <Card key={repo.id} className='gap-2'>
              <Text className='text-foreground font-semibold'>
                {repo.fullName}
              </Text>
              <Text className='text-muted-foreground text-xs'>
                {repo.private ? 'Private' : 'Public'} ·{' '}
                {repo.fork ? 'Fork' : 'Repository'} · {repo.defaultBranch}
              </Text>
              <Button
                disabled={submitting}
                variant='outline'
                onPress={() => confirmCreateFromRepo(repo)}
              >
                Create Spoon from metadata
              </Button>
            </Card>
          ))}
        </FormSection>
      )}
    </AppScreen>
  );
};

export default NewSpoonRoute;
