/**
 * ACP model/mode derivation — adapted from Paseo acp-agent.ts.
 */
import type {
  SessionConfigOption,
  SessionModelState,
  SessionModeState,
} from '@agentclientprotocol/sdk';
import type { ProviderMode, ProviderModel, ThinkingOption } from './provider-types.js';

type SelectConfigOption = Extract<SessionConfigOption, { type: 'select' }>;

interface SelectConfigChoice {
  value: string;
  name: string;
  description?: string | null;
  group?: string;
}

function findSelectConfigOption({
  configOptions,
  category,
  id,
}: {
  configOptions: SessionConfigOption[] | null | undefined;
  category: string;
  id?: string;
}): SelectConfigOption | null {
  const option = configOptions?.find(
    (entry): entry is SelectConfigOption =>
      entry.type === 'select' && entry.category === category && (!id || entry.id === id),
  );
  return option ?? null;
}

function flattenSelectOptions(options: SelectConfigOption['options']): SelectConfigChoice[] {
  const flattened: SelectConfigChoice[] = [];
  for (const option of options) {
    if ('value' in option) {
      flattened.push(option);
      continue;
    }
    for (const groupOption of option.options) {
      flattened.push({ ...groupOption, group: option.group });
    }
  }
  return flattened;
}

function deriveSelectorOptions(
  configOptions: SessionConfigOption[] | null | undefined,
  category: string,
): ThinkingOption[] {
  const option = findSelectConfigOption({ configOptions, category });
  if (!option) return [];

  return flattenSelectOptions(option.options).map((value) => ({
    id: value.value,
    label: value.name,
    isDefault: value.value === option.currentValue,
  }));
}

export function deriveModesFromACP(
  fallbackModes: ProviderMode[],
  modeState?: SessionModeState | null,
  configOptions?: SessionConfigOption[] | null,
): { modes: ProviderMode[]; currentModeId: string | null } {
  if (modeState?.availableModes?.length) {
    return {
      // ACP omits the unattended flag; inherit it from the manifest fallback by
      // id so the unified permission picker can still detect each agent's bypass
      // mode (e.g. opencode `full-access`) from live-probed modes.
      modes: modeState.availableModes.map((mode) => {
        const fb = fallbackModes.find((f) => f.id === mode.id);
        return {
          id: mode.id,
          label: mode.name,
          description: mode.description ?? undefined,
          ...(fb?.isUnattended ? { isUnattended: true } : {}),
        };
      }),
      currentModeId: modeState.currentModeId ?? null,
    };
  }

  const modeOption = findSelectConfigOption({ configOptions, category: 'mode' });
  if (modeOption) {
    const flatOptions = flattenSelectOptions(modeOption.options);
    return {
      modes: flatOptions.map((option) => ({
        id: option.value,
        label: option.name,
        description: option.description ?? undefined,
      })),
      currentModeId: modeOption.currentValue,
    };
  }

  return { modes: fallbackModes, currentModeId: null };
}

export function deriveModelDefinitionsFromACP(
  models: SessionModelState | null | undefined,
  configOptions?: SessionConfigOption[] | null,
): ProviderModel[] {
  const thinkingOptions = deriveSelectorOptions(configOptions, 'thought_level');
  const defaultThinkingOptionId = thinkingOptions.find((o) => o.isDefault)?.id;

  if (models?.availableModels?.length) {
    return models.availableModels.map((model) => ({
      id: model.modelId,
      label: model.name,
      description: model.description ?? undefined,
      isDefault: model.modelId === models.currentModelId,
      thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
      defaultThinkingOptionId: defaultThinkingOptionId ?? undefined,
    }));
  }

  const modelOptions = deriveSelectorOptions(configOptions, 'model');
  return modelOptions.map((option) => ({
    id: option.id,
    label: option.label,
    isDefault: option.isDefault,
    thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
    defaultThinkingOptionId: defaultThinkingOptionId ?? undefined,
  }));
}

export function findThoughtLevelConfigId(
  configOptions: SessionConfigOption[] | null | undefined,
): string | null {
  return findSelectConfigOption({ configOptions, category: 'thought_level' })?.id ?? null;
}
