import { config } from 'dotenv';
import { existsSync } from 'node:fs';
import { homedir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { detectFromEnv, loadConfig } from '@mosaicstack/config';

type TierSource =
  | 'process environment'
  | 'daemon .env'
  | 'monorepo-root .env'
  | 'gateway-local .env'
  | 'default';

type BootSource = TierSource | 'mosaic.config.json';

export interface GatewayDotenvPaths {
  daemonEnv: string;
  monorepoRootEnv: string;
  gatewayLocalEnv: string;
}

const here = dirname(fileURLToPath(import.meta.url));

export function resolveGatewayDotenvPaths(
  anchor: string = here,
  homeBase: string = homedir(),
): GatewayDotenvPaths {
  return {
    daemonEnv: join(homeBase, '.config', 'mosaic', 'gateway', '.env'),
    monorepoRootEnv: resolve(anchor, '../../..', '.env'),
    gatewayLocalEnv: resolve(anchor, '..', '.env'),
  };
}

export function resolveGatewayConfigPath(anchor: string = here): string {
  // GATEWAY_HOME is daemon-created 0700; its env override adds no authority because env can set MOSAIC_STORAGE_TIER.
  const gatewayHome = resolve(
    process.env['MOSAIC_GATEWAY_HOME'] ?? join(homedir(), '.config', 'mosaic', 'gateway'),
  );
  const daemonConfig = join(gatewayHome, 'mosaic.config.json');
  const gatewayLocalConfig = resolve(anchor, '..', 'mosaic.config.json');
  const monorepoRootConfig = resolve(anchor, '../../..', 'mosaic.config.json');

  if (existsSync(daemonConfig)) {
    return daemonConfig;
  }
  if (existsSync(gatewayLocalConfig)) {
    return gatewayLocalConfig;
  }
  if (existsSync(monorepoRootConfig)) {
    return monorepoRootConfig;
  }

  return monorepoRootConfig;
}

export function loadGatewayEnv(anchor: string = here, homeBase: string = homedir()): void {
  const { daemonEnv, monorepoRootEnv, gatewayLocalEnv } = resolveGatewayDotenvPaths(
    anchor,
    homeBase,
  );
  const inheritedTier = process.env['MOSAIC_STORAGE_TIER'];
  let tierSource: TierSource = inheritedTier === undefined ? 'default' : 'process environment';
  const inheritedDatabaseUrl = process.env['DATABASE_URL'];
  let databaseUrlSource: TierSource =
    inheritedDatabaseUrl === undefined ? 'default' : 'process environment';

  function loadAnchoredDotenv(
    path: string,
    sourceLabel: Exclude<TierSource, 'process environment' | 'default'>,
  ): void {
    if (!existsSync(path)) {
      return;
    }

    const beforeTier = process.env['MOSAIC_STORAGE_TIER'];
    const beforeDatabaseUrl = process.env['DATABASE_URL'];
    config({ path, quiet: true });

    if (
      beforeTier === undefined &&
      process.env['MOSAIC_STORAGE_TIER'] !== undefined &&
      tierSource === 'default'
    ) {
      tierSource = sourceLabel;
    }

    if (
      beforeDatabaseUrl === undefined &&
      process.env['DATABASE_URL'] !== undefined &&
      databaseUrlSource === 'default'
    ) {
      databaseUrlSource = sourceLabel;
    }
  }

  // Load .env from daemon config dir (global install / daemon mode) first.
  // It takes precedence over file-based local-dev configuration.
  loadAnchoredDotenv(daemonEnv, 'daemon .env');

  // Load .env from the anchored monorepo root, then fill any remaining values
  // from apps/gateway/.env when present.
  loadAnchoredDotenv(monorepoRootEnv, 'monorepo-root .env');
  loadAnchoredDotenv(gatewayLocalEnv, 'gateway-local .env');

  const envOnlyTier = detectFromEnv().tier;
  const configPath = resolveGatewayConfigPath(anchor);
  const anchoredConfigExists = existsSync(configPath);
  const resolvedTier = loadConfig(configPath).tier;
  const configuredTier = process.env['MOSAIC_STORAGE_TIER'];
  const databaseUrlDeterminesTier = envOnlyTier === 'standalone' && configuredTier !== 'standalone';
  const recognizedTierDeterminesTier =
    (configuredTier === 'federated' ||
      configuredTier === 'standalone' ||
      configuredTier === 'local') &&
    configuredTier === envOnlyTier;

  let source: BootSource;
  if (anchoredConfigExists) {
    source = 'mosaic.config.json';
  } else if (databaseUrlDeterminesTier && databaseUrlSource !== 'default') {
    source = databaseUrlSource;
  } else if (recognizedTierDeterminesTier && tierSource !== 'default') {
    source = tierSource;
  } else {
    source = 'default';
  }

  console.info(`[gateway env] storage tier=${resolvedTier} source=${source}`);
}

loadGatewayEnv();
