import {
  type CodexAppServerGetAccountParams,
  type CodexAppServerGetAccountRateLimitsResponse,
  type CodexAppServerGetAccountResponse,
  type CodexAppServerLogoutAccountResponse,
} from '@main/services/infrastructure/codexAppServer';

import type { CodexAppServerSessionFactory } from '@main/services/infrastructure/codexAppServer';

const ACCOUNT_READ_TIMEOUT_MS = 3_500;
const ACCOUNT_RATE_LIMITS_TIMEOUT_MS = 4_500;
const ACCOUNT_LOGOUT_TIMEOUT_MS = 3_500;
const INITIALIZE_TIMEOUT_MS = 6_000;
const TOTAL_TIMEOUT_MS = 9_000;
const TOTAL_WITH_RATE_LIMITS_TIMEOUT_MS = 15_000;

type CodexAccountRateLimitsReadResult =
  | { ok: true; payload: CodexAppServerGetAccountRateLimitsResponse }
  | { ok: false; error: unknown };

export class CodexAccountAppServerClient {
  constructor(private readonly sessionFactory: CodexAppServerSessionFactory) {}

  async readAccountSnapshot(options: {
    binaryPath: string;
    env: NodeJS.ProcessEnv;
    refreshToken?: boolean;
    includeRateLimits?: boolean;
  }): Promise<{
    account: CodexAppServerGetAccountResponse;
    rateLimits: CodexAccountRateLimitsReadResult | null;
    initialize: { codexHome: string; platformFamily: string; platformOs: string };
  }> {
    const includeRateLimits = options.includeRateLimits === true;

    return this.sessionFactory.withSession(
      {
        binaryPath: options.binaryPath,
        env: options.env,
        requestTimeoutMs: includeRateLimits
          ? ACCOUNT_RATE_LIMITS_TIMEOUT_MS
          : ACCOUNT_READ_TIMEOUT_MS,
        initializeTimeoutMs: INITIALIZE_TIMEOUT_MS,
        totalTimeoutMs: includeRateLimits ? TOTAL_WITH_RATE_LIMITS_TIMEOUT_MS : TOTAL_TIMEOUT_MS,
        label: includeRateLimits
          ? 'codex app-server account/read with rateLimits/read'
          : 'codex app-server account/read',
      },
      async (session) => {
        const account = await session.request<CodexAppServerGetAccountResponse>(
          'account/read',
          {
            refreshToken: options.refreshToken ?? false,
          } satisfies CodexAppServerGetAccountParams,
          ACCOUNT_READ_TIMEOUT_MS
        );

        let rateLimits: CodexAccountRateLimitsReadResult | null = null;
        if (includeRateLimits) {
          try {
            rateLimits = {
              ok: true,
              payload: await session.request<CodexAppServerGetAccountRateLimitsResponse>(
                'account/rateLimits/read',
                undefined,
                ACCOUNT_RATE_LIMITS_TIMEOUT_MS
              ),
            };
          } catch (error) {
            rateLimits = { ok: false, error };
          }
        }

        return {
          account,
          rateLimits,
          initialize: {
            codexHome: session.initializeResponse.codexHome,
            platformFamily: session.initializeResponse.platformFamily,
            platformOs: session.initializeResponse.platformOs,
          },
        };
      }
    );
  }

  async readAccount(options: {
    binaryPath: string;
    env: NodeJS.ProcessEnv;
    refreshToken?: boolean;
  }): Promise<{
    account: CodexAppServerGetAccountResponse;
    initialize: { codexHome: string; platformFamily: string; platformOs: string };
  }> {
    const result = await this.readAccountSnapshot(options);
    return {
      account: result.account,
      initialize: result.initialize,
    };
  }

  async readRateLimits(options: {
    binaryPath: string;
    env: NodeJS.ProcessEnv;
  }): Promise<CodexAppServerGetAccountRateLimitsResponse> {
    return this.sessionFactory.withSession(
      {
        binaryPath: options.binaryPath,
        env: options.env,
        requestTimeoutMs: ACCOUNT_RATE_LIMITS_TIMEOUT_MS,
        initializeTimeoutMs: INITIALIZE_TIMEOUT_MS,
        totalTimeoutMs: TOTAL_TIMEOUT_MS,
        label: 'codex app-server account/rateLimits/read',
      },
      async (session) =>
        session.request<CodexAppServerGetAccountRateLimitsResponse>(
          'account/rateLimits/read',
          undefined,
          ACCOUNT_RATE_LIMITS_TIMEOUT_MS
        )
    );
  }

  async logout(options: {
    binaryPath: string;
    env: NodeJS.ProcessEnv;
  }): Promise<CodexAppServerLogoutAccountResponse> {
    return this.sessionFactory.withSession(
      {
        binaryPath: options.binaryPath,
        env: options.env,
        requestTimeoutMs: ACCOUNT_LOGOUT_TIMEOUT_MS,
        initializeTimeoutMs: INITIALIZE_TIMEOUT_MS,
        totalTimeoutMs: TOTAL_TIMEOUT_MS,
        label: 'codex app-server account/logout',
      },
      async (session) =>
        session.request<CodexAppServerLogoutAccountResponse>(
          'account/logout',
          undefined,
          ACCOUNT_LOGOUT_TIMEOUT_MS
        )
    );
  }
}
