import {
  runAllHealthChecks,
  formatHealthCheckError,
} from './health-checks.js';
import { readFileSync } from 'fs';
import { join } from 'path';

const DEFAULT_RPC_URL = 'http://localhost:8081/api/rpc';
const DEFAULT_WEBAPP_URL = 'http://localhost:8081';
const DEFAULT_GRAPHQL_URL = 'http://localhost:8081/api/graphql';

export interface ContractAddresses {
  Kraiken: string;
  Stake: string;
  LiquidityManager: string;
  OptimizerProxy?: string;
}

export interface StackConfig {
  rpcUrl: string;
  webAppUrl: string;
  graphqlUrl: string;
  contracts: ContractAddresses;
}

/**
 * Load contract addresses, preferring env var overrides over the deployments file.
 * Env vars: STACK_KRAIKEN_ADDRESS, STACK_STAKE_ADDRESS, STACK_LM_ADDRESS.
 * Falls back to onchain/deployments-local.json when env vars are absent.
 */
function loadContractAddresses(): ContractAddresses {
  const envKraiken = process.env.STACK_KRAIKEN_ADDRESS;
  const envStake = process.env.STACK_STAKE_ADDRESS;
  const envLm = process.env.STACK_LM_ADDRESS;

  if (envKraiken && envStake && envLm) {
    const envOptimizerProxy = process.env.STACK_OPTIMIZER_PROXY_ADDRESS;
    return {
      Kraiken: envKraiken,
      Stake: envStake,
      LiquidityManager: envLm,
      ...(envOptimizerProxy !== undefined ? { OptimizerProxy: envOptimizerProxy } : {}),
    };
  }

  let fileContracts!: ContractAddresses;
  try {
    const deploymentsPath = join(process.cwd(), 'onchain', 'deployments-local.json');
    const deploymentsJson = readFileSync(deploymentsPath, 'utf-8');
    const deployments = JSON.parse(deploymentsJson);
    fileContracts = deployments.contracts;
  } catch (error) {
    console.error('Failed to load contract addresses from deployments-local.json:', error);
    throw new Error('Cannot run tests without deployed contract addresses');
  }

  return {
    Kraiken: envKraiken ?? fileContracts.Kraiken,
    Stake: envStake ?? fileContracts.Stake,
    LiquidityManager: envLm ?? fileContracts.LiquidityManager,
    ...(fileContracts.OptimizerProxy !== undefined
      ? { OptimizerProxy: fileContracts.OptimizerProxy }
      : {}),
  };
}

/**
 * Get stack configuration from environment variables.
 * Tests should NOT start their own stack - they require a pre-existing healthy stack.
 */
export function getStackConfig(): StackConfig {
  return {
    rpcUrl: process.env.STACK_RPC_URL ?? DEFAULT_RPC_URL,
    webAppUrl: process.env.STACK_WEBAPP_URL ?? DEFAULT_WEBAPP_URL,
    graphqlUrl: process.env.STACK_GRAPHQL_URL ?? DEFAULT_GRAPHQL_URL,
    contracts: loadContractAddresses(),
  };
}

/**
 * Validate that a healthy stack exists and is functional.
 * If validation fails, the test run should exit immediately.
 *
 * Tests do NOT manage stack lifecycle - stack must be started externally via:
 *   ./scripts/dev.sh start
 */
export async function validateStackHealthy(config: StackConfig): Promise<void> {
  const results = await runAllHealthChecks(config);

  const failures = results.filter(r => !r.success);
  if (failures.length > 0) {
    const errorMessage = formatHealthCheckError(results);
    console.error('\n❌ Stack health validation failed');
    console.error('Tests require a pre-existing healthy stack.');
    console.error('Start the stack with: ./scripts/dev.sh start\n');
    console.error(errorMessage);
    process.exit(1);
  }

  console.log('✅ Stack health validation passed');
}
