import { ConfirmInput, TextInput } from '@inkjs/ui';
import { Box, Text } from 'ink';
import { useEffect, useState } from 'react';
import { suggestOutputFile } from '../suggestOutputFile.js';
import { configExists, writeConfig } from '../writeConfig.js';
import { EntriesList } from './entriesList.js';
import type { Entry } from '../types.js';

export type InitStatus = 'written' | 'aborted';

export interface InitCommandProps {
    onComplete: (status: InitStatus) => void;
}

type State =
    | { phase: 'confirm-overwrite' }
    | { phase: 'aborted' }
    | { phase: 'ask-output-dir' }
    | {
          phase: 'ask-schema';
          outputDir: string;
          entries: Entry[];
          error?: string;
          attempt: number;
      }
    | {
          phase: 'ask-output';
          outputDir: string;
          entries: Entry[];
          schemaUrl: string;
          error?: string;
          attempt: number;
      }
    | { phase: 'writing'; entries: Entry[] }
    | { phase: 'done'; entries: Entry[]; path: string }
    | { phase: 'error'; message: string };

function initialState(): State {
    return configExists() ? { phase: 'confirm-overwrite' } : { phase: 'ask-output-dir' };
}

export function InitCommand(props: InitCommandProps) {
    const [state, setState] = useState<State>(initialState);

    useEffect(() => {
        if (state.phase !== 'writing') return;

        try {
            const targetPath = writeConfig({ entries: state.entries });

            setState({
                phase: 'done',
                entries: state.entries,
                path: targetPath,
            });
        } catch (err) {
            setState({
                phase: 'error',
                message: err instanceof Error ? err.message : String(err),
            });
        }
    }, [state]);

    useEffect(() => {
        if (state.phase === 'done') props.onComplete('written');
        if (state.phase === 'aborted') props.onComplete('aborted');
        if (state.phase === 'error') props.onComplete('aborted');
    }, [state, props.onComplete]);

    if (state.phase === 'confirm-overwrite') {
        return (
            <Box flexDirection="column">
                <Text color="yellow">
                    openapi-typescript.config.ts already exists in this directory.
                </Text>
                <Box>
                    <Text>Overwrite? (y/N) </Text>
                    <ConfirmInput
                        defaultChoice="cancel"
                        onConfirm={() => setState({ phase: 'ask-output-dir' })}
                        onCancel={() => setState({ phase: 'aborted' })}
                    />
                </Box>
            </Box>
        );
    }

    if (state.phase === 'aborted') {
        return (
            <Box flexDirection="column">
                <Text color="yellow">Aborted. Existing config left untouched.</Text>
                <Text color="gray">Delete or move the file, then run init again.</Text>
            </Box>
        );
    }

    if (state.phase === 'ask-output-dir') {
        const handleSubmit = (value: string) => {
            setState({
                phase: 'ask-schema',
                outputDir: value.trim(),
                entries: [],
                attempt: 0,
            });
        };

        return (
            <Box flexDirection="column">
                <Text color="gray">
                    Where should generated types live? Leave empty to write them next to the config.
                </Text>
                <Box>
                    <Text>Output directory: </Text>
                    <TextInput defaultValue="generated" onSubmit={handleSubmit} />
                </Box>
            </Box>
        );
    }

    if (state.phase === 'ask-schema') {
        const hasEntries = state.entries.length > 0;
        const placeholder = hasEntries
            ? 'https://api.example.com/openapi.json (or press enter to finish)'
            : 'https://api.example.com/openapi.json';

        const handleSubmit = (value: string) => {
            const trimmed = value.trim();

            if (!trimmed) {
                if (hasEntries) {
                    setState({
                        phase: 'writing',
                        entries: state.entries,
                    });

                    return;
                }

                setState({
                    phase: 'ask-schema',
                    outputDir: state.outputDir,
                    entries: state.entries,
                    error: 'Schema URL is required',
                    attempt: state.attempt + 1,
                });

                return;
            }

            setState({
                phase: 'ask-output',
                outputDir: state.outputDir,
                entries: state.entries,
                schemaUrl: trimmed,
                attempt: 0,
            });
        };

        return (
            <Box flexDirection="column">
                <EntriesList entries={state.entries} />
                {state.error ? <Text color="red">{state.error}</Text> : null}
                <Box>
                    <Text>Schema URL: </Text>
                    <TextInput
                        key={`${state.entries.length}-${state.attempt}`}
                        placeholder={placeholder}
                        onSubmit={handleSubmit}
                    />
                </Box>
            </Box>
        );
    }

    if (state.phase === 'ask-output') {
        const suggestion = suggestOutputFile(state.schemaUrl, state.entries, state.outputDir);

        const handleSubmit = (value: string) => {
            const proposed = value.trim() || suggestion;
            const collision = state.entries.some((e) => e.outputFile === proposed);

            if (collision) {
                setState({
                    phase: 'ask-output',
                    outputDir: state.outputDir,
                    entries: state.entries,
                    schemaUrl: state.schemaUrl,
                    error: `Output file '${proposed}' is already used by a previous entry — pick a different name.`,
                    attempt: state.attempt + 1,
                });

                return;
            }

            setState({
                phase: 'ask-schema',
                outputDir: state.outputDir,
                entries: [
                    ...state.entries,
                    {
                        schemaUrl: state.schemaUrl,
                        outputFile: proposed,
                    },
                ],
                attempt: 0,
            });
        };

        return (
            <Box flexDirection="column">
                <EntriesList entries={state.entries} />
                <Text color="gray">Schema URL: {state.schemaUrl}</Text>
                {state.error ? <Text color="red">{state.error}</Text> : null}
                <Box>
                    <Text>Output file: </Text>
                    <TextInput
                        key={state.attempt}
                        defaultValue={suggestion}
                        onSubmit={handleSubmit}
                    />
                </Box>
            </Box>
        );
    }

    if (state.phase === 'writing') {
        return <Text color="cyan">Writing config…</Text>;
    }

    if (state.phase === 'done') {
        return (
            <Box flexDirection="column">
                <EntriesList entries={state.entries} />
                <Text color="green">
                    ✔ Wrote openapi-typescript.config.ts ({state.entries.length}{' '}
                    {state.entries.length === 1 ? 'entry' : 'entries'}) to {state.path}
                </Text>
            </Box>
        );
    }

    return <Text color="red">✖ {state.message}</Text>;
}
