import chalk from 'chalk';
import figures from 'figures';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { Text } from '@anthropic/ink';
import { useKeybinding } from '../keybindings/useKeybinding.js';
import { toError } from '../utils/errors.js';
import { logError } from '../utils/log.js';
import { getSettingSourceName, type SettingSource } from '../utils/settings/constants.js';
import { updateSettingsForSource } from '../utils/settings/settings.js';
import { getEnvironmentSelectionInfo } from '../utils/teleport/environmentSelection.js';
import type { EnvironmentResource } from '../utils/teleport/environments.js';
import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js';
import { Select } from './CustomSelect/select.js';
import { Byline, Dialog, KeyboardShortcutHint, LoadingState } from '@anthropic/ink';

const DIALOG_TITLE = 'Select Remote Environment';
const SETUP_HINT = `Configure environments at: https://claude.ai/code`;

type Props = {
  onDone: (message?: string) => void;
};

type LoadingState = 'loading' | 'updating' | null;

export function RemoteEnvironmentDialog({ onDone }: Props): React.ReactNode {
  const [loadingState, setLoadingState] = useState<LoadingState>('loading');
  const [environments, setEnvironments] = useState<EnvironmentResource[]>([]);
  const [selectedEnvironment, setSelectedEnvironment] = useState<EnvironmentResource | null>(null);
  const [selectedEnvironmentSource, setSelectedEnvironmentSource] = useState<SettingSource | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    async function fetchInfo(): Promise<void> {
      try {
        const result = await getEnvironmentSelectionInfo();
        if (cancelled) return;
        setEnvironments(result.availableEnvironments);
        setSelectedEnvironment(result.selectedEnvironment);
        setSelectedEnvironmentSource(result.selectedEnvironmentSource);
        setLoadingState(null);
      } catch (err) {
        if (cancelled) return;
        const fetchError = toError(err);
        logError(fetchError);
        setError(fetchError.message);
        setLoadingState(null);
      }
    }
    void fetchInfo();
    return () => {
      cancelled = true;
    };
  }, []);

  function handleSelect(value: string): void {
    if (value === 'cancel') {
      onDone();
      return;
    }

    setLoadingState('updating');

    const selectedEnv = environments.find(env => env.environment_id === value);

    if (!selectedEnv) {
      onDone('Error: Selected environment not found');
      return;
    }

    updateSettingsForSource('localSettings', {
      remote: {
        defaultEnvironmentId: selectedEnv.environment_id,
      },
    });

    onDone(`Set default remote environment to ${chalk.bold(selectedEnv.name)} (${selectedEnv.environment_id})`);
  }

  // Loading state
  if (loadingState === 'loading') {
    return (
      <Dialog title={DIALOG_TITLE} onCancel={onDone} hideInputGuide>
        <LoadingState message="Loading environments…" />
      </Dialog>
    );
  }

  // Error state
  if (error) {
    return (
      <Dialog title={DIALOG_TITLE} onCancel={onDone}>
        <Text color="error">Error: {error}</Text>
      </Dialog>
    );
  }

  // No environments available
  if (!selectedEnvironment) {
    return (
      <Dialog title={DIALOG_TITLE} subtitle={SETUP_HINT} onCancel={onDone}>
        <Text>No remote environments available.</Text>
      </Dialog>
    );
  }

  // Single environment - just show info
  if (environments.length === 1) {
    return <SingleEnvironmentContent environment={selectedEnvironment} onDone={onDone} />;
  }

  // Multiple environments - show selection UI
  return (
    <MultipleEnvironmentsContent
      environments={environments}
      selectedEnvironment={selectedEnvironment}
      selectedEnvironmentSource={selectedEnvironmentSource}
      loadingState={loadingState}
      onSelect={handleSelect}
      onCancel={onDone}
    />
  );
}

function EnvironmentLabel({ environment }: { environment: EnvironmentResource }): React.ReactNode {
  return (
    <Text>
      {figures.tick} Using <Text bold>{environment.name}</Text> <Text dimColor>({environment.environment_id})</Text>
    </Text>
  );
}

function SingleEnvironmentContent({
  environment,
  onDone,
}: {
  environment: EnvironmentResource;
  onDone: () => void;
}): React.ReactNode {
  // Handle Enter to continue
  useKeybinding('confirm:yes', onDone, { context: 'Confirmation' });

  return (
    <Dialog title={DIALOG_TITLE} subtitle={SETUP_HINT} onCancel={onDone}>
      <EnvironmentLabel environment={environment} />
    </Dialog>
  );
}

function MultipleEnvironmentsContent({
  environments,
  selectedEnvironment,
  selectedEnvironmentSource,
  loadingState,
  onSelect,
  onCancel,
}: {
  environments: EnvironmentResource[];
  selectedEnvironment: EnvironmentResource;
  selectedEnvironmentSource: SettingSource | null;
  loadingState: LoadingState;
  onSelect: (value: string) => void;
  onCancel: () => void;
}): React.ReactNode {
  const sourceSuffix =
    selectedEnvironmentSource && selectedEnvironmentSource !== 'localSettings'
      ? ` (from ${getSettingSourceName(selectedEnvironmentSource)} settings)`
      : '';

  const subtitle = (
    <Text>
      Currently using: <Text bold>{selectedEnvironment.name}</Text>
      {sourceSuffix}
    </Text>
  );

  return (
    <Dialog title={DIALOG_TITLE} subtitle={subtitle} onCancel={onCancel} hideInputGuide>
      <Text dimColor>{SETUP_HINT}</Text>
      {loadingState === 'updating' ? (
        <LoadingState message="Updating…" />
      ) : (
        <Select
          options={environments.map(env => ({
            label: (
              <Text>
                {env.name} <Text dimColor>({env.environment_id})</Text>
              </Text>
            ),
            value: env.environment_id,
          }))}
          defaultValue={selectedEnvironment.environment_id}
          onChange={onSelect}
          onCancel={() => onSelect('cancel')}
          layout="compact-vertical"
        />
      )}
      <Text dimColor>
        <Byline>
          <KeyboardShortcutHint shortcut="Enter" action="select" />
          <ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="cancel" />
        </Byline>
      </Text>
    </Dialog>
  );
}
