/**
 * Client configuration wizard (TUI) with auto-discovery and multi-server support
 */

import { Box, render, Text } from 'ink';
import TextInput from 'ink-text-input';
import React, { useState } from 'react';
import { TCPClient } from '../protocol/socket.js';
import { MessageType } from '../protocol/types.js';
import type { DeviceInfo } from '../types/common.js';
import { getConfigPaths, saveClientConfig } from './manager.js';
import type { ClientConfig, DeviceConfig, ServerConnection } from './schema.js';

interface WizardState {
  step:
    | 'clientId'
    | 'serverName'
    | 'serverAddress'
    | 'serverPort'
    | 'discovering'
    | 'selectDevices'
    | 'addAnother'
    | 'done';
  config: Partial<ClientConfig>;
  currentServer?: Partial<ServerConnection>;
  discoveredDevices?: DeviceInfo[];
  discoveryError?: string;
}

function ClientConfigWizard() {
  const [state, setState] = useState<WizardState>({
    step: 'clientId',
    config: {
      servers: [],
    },
  });

  const [input, setInput] = useState('');

  const handleSubmit = async (value: string) => {
    const newState = { ...state };

    switch (state.step) {
      case 'clientId':
        newState.config.clientId = value;
        newState.step = 'serverName';
        break;

      case 'serverName':
        newState.currentServer = {
          name: value,
          devices: [],
        };
        newState.step = 'serverAddress';
        break;

      case 'serverAddress':
        if (newState.currentServer) {
          newState.currentServer.address = value;
        }
        newState.step = 'serverPort';
        break;

      case 'serverPort':
        if (newState.currentServer) {
          newState.currentServer.port = Number.parseInt(value, 10) || 3240;
        }
        // Start auto-discovery
        newState.step = 'discovering';
        setState(newState);
        setInput('');
        await discoverDevices(newState);
        return;

      case 'selectDevices':
        if (value === 'done') {
          // Add current server to config
          if (
            newState.currentServer &&
            newState.currentServer.name &&
            newState.currentServer.address &&
            newState.currentServer.port
          ) {
            const servers = newState.config.servers || [];
            servers.push(newState.currentServer as ServerConnection);
            newState.config.servers = servers;
            newState.currentServer = undefined;
            newState.discoveredDevices = undefined;
            newState.step = 'addAnother';
          }
        } else if (value) {
          // Add device by index
          const index = Number.parseInt(value, 10);
          if (
            !Number.isNaN(index) &&
            newState.discoveredDevices &&
            index >= 0 &&
            index < newState.discoveredDevices.length
          ) {
            const selectedDevice = newState.discoveredDevices[index];
            if (selectedDevice) {
              const device: DeviceConfig = {
                path: selectedDevice.path,
                vendorId: selectedDevice.vendorId,
                productId: selectedDevice.productId,
                description: selectedDevice.description,
              };
              if (newState.currentServer) {
                newState.currentServer.devices = [
                  ...(newState.currentServer.devices || []),
                  device,
                ];
              }
            }
          }
        }
        break;

      case 'addAnother':
        if (value.toLowerCase() === 'y' || value.toLowerCase() === 'yes') {
          newState.step = 'serverName';
        } else {
          // Done adding servers, save config
          newState.step = 'done';
          try {
            await saveClientConfig(newState.config as ClientConfig);
            console.log(`\nConfiguration saved to ${getConfigPaths().client}`);
            process.exit(0);
          } catch (error) {
            console.error(`\nFailed to save config: ${error}`);
            process.exit(1);
          }
        }
        break;
    }

    setState(newState);
    setInput('');
  };

  const discoverDevices = async (currentState: WizardState) => {
    const server = currentState.currentServer;
    if (!server || !server.address || !server.port || !currentState.config.clientId) {
      setState({
        ...currentState,
        discoveryError: 'Missing server information',
        step: 'selectDevices',
      });
      return;
    }

    try {
      // Connect to server
      const client = new TCPClient(server.address, server.port);

      const discoveredDevices = await new Promise<DeviceInfo[]>((resolve, reject) => {
        const timeout = setTimeout(() => {
          client.disconnect();
          reject(new Error('Discovery timeout'));
        }, 5000);

        client.onMessage((message) => {
          if (message.type === MessageType.DEVICE_LIST_RESPONSE) {
            clearTimeout(timeout);
            client.disconnect();
            resolve(message.devices);
          }
        });

        client.onConnectionState((connected) => {
          if (connected) {
            // Send device list request
            client.send({
              type: MessageType.DEVICE_LIST_REQUEST,
              timestamp: Date.now(),
              clientId: currentState.config.clientId!,
            });
          }
        });

        client.connect().catch(reject);
      });

      setState({
        ...currentState,
        discoveredDevices,
        step: 'selectDevices',
      });
    } catch (error) {
      setState({
        ...currentState,
        discoveryError: `Discovery failed: ${error}`,
        discoveredDevices: [],
        step: 'selectDevices',
      });
    }
  };

  return (
    <Box flexDirection="column" padding={1}>
      <Text bold color="cyan">
        USB/IP Supervisor - Client Configuration
      </Text>
      <Text> </Text>

      {state.step === 'clientId' && (
        <>
          <Text>Client ID (unique identifier):</Text>
          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}

      {state.step === 'serverName' && (
        <>
          <Text>Server name (e.g., "office-server", "lab-server"):</Text>
          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}

      {state.step === 'serverAddress' && (
        <>
          <Text>Server address (IP or hostname):</Text>
          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}

      {state.step === 'serverPort' && (
        <>
          <Text>Server port (default: 3240):</Text>
          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}

      {state.step === 'discovering' && (
        <>
          <Text color="yellow">🔍 Discovering devices from {state.currentServer?.name}...</Text>
        </>
      )}

      {state.step === 'selectDevices' && (
        <>
          {state.discoveryError && (
            <>
              <Text color="red">❌ {state.discoveryError}</Text>
              <Text dimColor>You can still configure devices manually</Text>
              <Text> </Text>
            </>
          )}

          <Text bold>Available devices from {state.currentServer?.name}:</Text>
          <Text> </Text>

          {state.discoveredDevices && state.discoveredDevices.length > 0 ? (
            state.discoveredDevices.map((d, i) => (
              <Text key={d.path}>
                [{i}] {d.vendorId}:{d.productId} - {d.description}
                <Text dimColor> ({d.path})</Text>
              </Text>
            ))
          ) : (
            <Text color="yellow">No devices discovered</Text>
          )}

          <Text> </Text>
          <Text dimColor>Enter index to select device, or 'done' to finish this server</Text>
          <Text> </Text>

          {state.currentServer?.devices && state.currentServer.devices.length > 0 && (
            <>
              <Text color="green">Selected devices:</Text>
              {state.currentServer.devices.map((d, i) => (
                <Text key={i}>
                  - {d.vendorId}:{d.productId} - {d.description}
                </Text>
              ))}
              <Text> </Text>
            </>
          )}

          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}

      {state.step === 'addAnother' && (
        <>
          <Text bold color="green">
            ✓ Server "{state.config.servers?.[state.config.servers.length - 1]?.name}" configured
          </Text>
          <Text> </Text>
          <Text>Add another server? (y/n):</Text>
          <TextInput value={input} onChange={setInput} onSubmit={handleSubmit} />
        </>
      )}
    </Box>
  );
}

export async function runClientConfigWizard(): Promise<void> {
  render(<ClientConfigWizard />);
}
