import fs from 'fs';
import path from 'path';

export type OmnlAuthRole = 'super_admin' | 'customer' | 'portal_internal' | 'legacy_operator';

export type OmnlPrincipal = {
  role: OmnlAuthRole;
  adminId?: string;
  portalCtid?: number;
  scopes?: string[];
};

export type SuperAdminEntry = {
  id: string;
  username: string;
  displayName: string;
  portalCtid: number;
  portalName: string;
  envKey: string;
  fineractUser: string;
  products: string[];
};

export type CustomerSecurityPolicy = {
  version: string;
  production: boolean;
  neverExposeOperatorKeyInBrowser: boolean;
  portalInjectAuthViaNginx: boolean;
  requireApiKeyAllExchangeRoutes: boolean;
  customerAllowedScopes: string[];
  superAdminOnlyScopes: string[];
  rateLimits: {
    customerPerMinute: number;
    superAdminPerMinute: number;
    anonymousPerMinute: number;
  };
  corsOrigins: string[];
};

let superAdminCache: SuperAdminEntry[] | null = null;

function repoRoot(): string {
  return process.env.OMNL_BANK_ROOT || process.env.REPO_ROOT || process.cwd();
}

export function loadSuperAdminRegistry(): SuperAdminEntry[] {
  if (superAdminCache) return superAdminCache;
  const configPath =
    process.env.OMNL_SUPER_ADMINS_CONFIG ||
    path.join(repoRoot(), 'config/omnl-super-admins.v1.json');
  try {
    const raw = JSON.parse(fs.readFileSync(configPath, 'utf8')) as { superAdmins: SuperAdminEntry[] };
    superAdminCache = raw.superAdmins ?? [];
  } catch {
    superAdminCache = [];
  }
  return superAdminCache;
}

export function extractApiKey(req: {
  headers: Record<string, unknown>;
  query?: Record<string, unknown>;
}): string | undefined {
  const auth = String(req.headers.authorization || '');
  const bearer = auth.startsWith('Bearer ') ? auth.slice(7).trim() : '';
  const headerKey = String(req.headers['x-api-key'] ?? '').trim();
  const q = String(req.query?.access_token ?? '').trim();
  return bearer || headerKey || q || undefined;
}

function customerKeys(): Map<string, string[]> {
  const map = new Map<string, string[]>();
  const policy = loadCustomerSecurityPolicy();
  const scopes = policy.customerAllowedScopes;
  const raw = process.env.OMNL_CUSTOMER_API_KEYS?.trim();
  if (raw) {
    for (const part of raw.split(',').map((s) => s.trim()).filter(Boolean)) {
      const [key, scopeList] = part.split(':');
      if (!key) continue;
      map.set(
        key.trim(),
        scopeList ? scopeList.split('|').map((s) => s.trim()).filter(Boolean) : scopes,
      );
    }
  }
  for (const envKey of ['OMNL_CUSTOMER_API_KEY_1', 'OMNL_CUSTOMER_API_KEY_2', 'OMNL_CUSTOMER_API_KEY_3']) {
    const val = process.env[envKey]?.trim();
    if (val) map.set(val, scopes);
  }
  return map;
}

export function loadCustomerSecurityPolicy(): CustomerSecurityPolicy {
  const configPath =
    process.env.OMNL_CUSTOMER_SECURITY_CONFIG ||
    path.join(repoRoot(), 'config/omnl-customer-security.production.v1.json');
  try {
    return JSON.parse(fs.readFileSync(configPath, 'utf8')) as CustomerSecurityPolicy;
  } catch {
    return {
      version: '1.0.0',
      production: true,
      neverExposeOperatorKeyInBrowser: true,
      portalInjectAuthViaNginx: true,
      requireApiKeyAllExchangeRoutes: true,
      customerAllowedScopes: ['read', 'trade'],
      superAdminOnlyScopes: ['settle', 'token_load', 'transfer', 'admin'],
      rateLimits: { customerPerMinute: 30, superAdminPerMinute: 120, anonymousPerMinute: 0 },
      corsOrigins: [],
    };
  }
}

function portalInternalOk(req: { headers: Record<string, unknown> }): boolean {
  const secret = process.env.OMNL_PORTAL_INTERNAL_SECRET?.trim();
  if (!secret) return false;
  const header = String(req.headers['x-omnl-portal-auth'] ?? '').trim();
  return header === secret;
}

export function resolveOmnlPrincipal(
  req: { headers: Record<string, unknown>; query?: Record<string, unknown> },
  key?: string,
): OmnlPrincipal | null {
  if (portalInternalOk(req)) {
    return { role: 'portal_internal', scopes: ['read', 'trade', 'settle', 'token_load', 'transfer', 'admin'] };
  }

  const apiKey = key ?? extractApiKey(req);
  if (!apiKey) return null;

  const legacy = process.env.OMNL_API_KEY?.trim();
  if (legacy && apiKey === legacy) {
    return { role: 'legacy_operator', scopes: ['read', 'trade', 'settle', 'token_load', 'transfer', 'admin'] };
  }

  for (const admin of loadSuperAdminRegistry()) {
    const adminKey = process.env[admin.envKey]?.trim();
    if (adminKey && apiKey === adminKey) {
      return {
        role: 'super_admin',
        adminId: admin.id,
        portalCtid: admin.portalCtid,
        scopes: ['read', 'trade', 'settle', 'token_load', 'transfer', 'admin'],
      };
    }
  }

  const customers = customerKeys();
  const customerScopes = customers.get(apiKey);
  if (customerScopes) {
    return { role: 'customer', scopes: customerScopes };
  }

  return null;
}

export function principalHasScope(principal: OmnlPrincipal | null, scope: string): boolean {
  if (!principal) return false;
  if (principal.role === 'super_admin' || principal.role === 'legacy_operator' || principal.role === 'portal_internal') {
    return true;
  }
  return (principal.scopes ?? []).includes(scope);
}

export function isProductionSecurityMode(): boolean {
  const policy = loadCustomerSecurityPolicy();
  return (
    policy.production ||
    process.env.OMNL_CUSTOMER_SECURITY_PRODUCTION === '1' ||
    (process.env.NODE_ENV || '').toLowerCase() === 'production'
  );
}
