import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ManagedSession } from '../../session/index.js';
import type { ModelClient } from '../../models/types.js';
import type { ModelRouter } from '../../models/router.js';

const {
  mockLoadStoredAnthropicAuth,
  mockLoadStoredAnthropicAuthToken,
  mockStoreAnthropicAuth,
} = vi.hoisted(() => ({
  mockLoadStoredAnthropicAuth: vi.fn(),
  mockLoadStoredAnthropicAuthToken: vi.fn(),
  mockStoreAnthropicAuth: vi.fn(),
}));

const { mockCreateInterface } = vi.hoisted(() => ({
  mockCreateInterface: vi.fn(),
}));

vi.mock('../../auth/index.js', () => ({
  loadStoredAnthropicAuth: mockLoadStoredAnthropicAuth,
  loadStoredAnthropicAuthToken: mockLoadStoredAnthropicAuthToken,
  loadStoredOpenAIApiKey: vi.fn(),
  loadStoredOpenAIAuth: vi.fn(),
  loadStoredZaiAuth: vi.fn(),
  loginGitHub: vi.fn(),
  loginOpenAI: vi.fn(),
  storeAnthropicAuth: mockStoreAnthropicAuth,
  storeAnthropicAuthToken: vi.fn(),
  storeOpenAIApiKey: vi.fn(),
  storeZaiAuth: vi.fn(),
}));

vi.mock('node:readline', () => ({
  createInterface: mockCreateInterface,
  emitKeypressEvents: vi.fn(),
}));

function asSession(value: unknown): ManagedSession {
  return value as ManagedSession;
}

function asModelClient(value: unknown): ModelClient {
  return value as ModelClient;
}

function asModelRouter(value: unknown): ModelRouter {
  return value as ModelRouter;
}

function minimalTuiPrivates(value: unknown): {
  rl: { pause: () => void; resume: () => void };
  prompt: (text: string) => Promise<string>;
  handleLoginCommand: (provider: string) => Promise<void>;
} {
  return value as {
    rl: { pause: () => void; resume: () => void };
    prompt: (text: string) => Promise<string>;
    handleLoginCommand: (provider: string) => Promise<void>;
  };
}

describe('MinimalTui login re-auth confirmation', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockLoadStoredAnthropicAuth.mockReset();
    mockLoadStoredAnthropicAuthToken.mockReset();
    mockStoreAnthropicAuth.mockReset();
    mockCreateInterface.mockReset();
  });

  it('cancels anthropic API-key re-auth when user answers no', async () => {
    mockLoadStoredAnthropicAuth.mockReturnValue({ api_key: 'existing-key', created_at: '2026-02-16T00:00:00.000Z' });
    mockLoadStoredAnthropicAuthToken.mockReturnValue(null);

    const { MinimalTui } = await import('./minimal.js');

    const mockSession = {
      id: 'test',
      getHistory: () => [],
      addMessage: vi.fn(),
      clear: vi.fn(),
      replaceHistory: vi.fn(),
    };

    const tui = new MinimalTui({
      session: asSession(mockSession),
      modelClient: asModelClient({}),
      modelRouter: asModelRouter({}),
      systemPrompt: 'test',
    });

    minimalTuiPrivates(tui).rl = { pause: vi.fn(), resume: vi.fn() };
    const promptMock = vi.spyOn(minimalTuiPrivates(tui), 'prompt')
      .mockResolvedValueOnce('')  // default -> API key path
      .mockResolvedValueOnce('n'); // confirmation

    const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => undefined);

    await minimalTuiPrivates(tui).handleLoginCommand('anthropic');

    expect(promptMock).toHaveBeenCalled();
    expect(mockStoreAnthropicAuth).not.toHaveBeenCalled();
    expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('Cancelled.'));

    consoleLog.mockRestore();
  });

  it('overwrites anthropic API key when user answers yes', async () => {
    mockLoadStoredAnthropicAuth.mockReturnValue({ api_key: 'existing-key', created_at: '2026-02-16T00:00:00.000Z' });
    mockLoadStoredAnthropicAuthToken.mockReturnValue(null);
    mockCreateInterface.mockImplementation(() => ({
      question: (_q: string, cb: (ans: string) => void) => cb('new-anthropic-key'),
      close: () => undefined,
    }));

    const { MinimalTui } = await import('./minimal.js');

    const mockSession = {
      id: 'test',
      getHistory: () => [],
      addMessage: vi.fn(),
      clear: vi.fn(),
      replaceHistory: vi.fn(),
    };

    const tui = new MinimalTui({
      session: asSession(mockSession),
      modelClient: asModelClient({}),
      modelRouter: asModelRouter({}),
      systemPrompt: 'test',
    });

    const pause = vi.fn();
    const resume = vi.fn();
    minimalTuiPrivates(tui).rl = { pause, resume };
    vi.spyOn(minimalTuiPrivates(tui), 'prompt')
      .mockResolvedValueOnce('')   // default -> API key path
      .mockResolvedValueOnce('y'); // confirmation

    const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => undefined);
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);

    await minimalTuiPrivates(tui).handleLoginCommand('anthropic');

    expect(mockStoreAnthropicAuth).toHaveBeenCalledWith('new-anthropic-key');
    expect(pause).toHaveBeenCalled();
    expect(resume).toHaveBeenCalled();
    expect(consoleError).not.toHaveBeenCalled();

    consoleLog.mockRestore();
    consoleError.mockRestore();
  });
});
