import { config } from 'dotenv';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
config({ path: path.resolve(fileURLToPath(import.meta.url), '../../../../.env') });

/**
 * api-gateway — прокси к микросервисам
 * web-svc = только UI, вся логика и API здесь
 * docs/architecture: 02-k3s-microservices-spec.md §5
 */

import Fastify, { FastifyRequest, FastifyReply } from 'fastify';
import cors from '@fastify/cors';

const PORT = parseInt(process.env.PORT ?? '3015', 10);

const SVC: Record<string, string> = {
  chat: process.env.CHAT_SVC_URL ?? 'http://localhost:3005',
  library: process.env.LIBRARY_SVC_URL ?? 'http://localhost:3009',
  discover: process.env.DISCOVER_SVC_URL ?? 'http://localhost:3002',
  search: process.env.SEARCH_SVC_URL ?? 'http://localhost:3001',
  finance: process.env.FINANCE_SVC_URL ?? 'http://localhost:3003',
  travel: process.env.TRAVEL_SVC_URL ?? 'http://localhost:3004',
  create: process.env.CREATE_SVC_URL ?? 'http://localhost:3011',
  memory: process.env.MEMORY_SVC_URL ?? 'http://localhost:3010',
  projects: process.env.PROJECTS_SVC_URL ?? 'http://localhost:3006',
  notifications: process.env.NOTIFICATIONS_SVC_URL ?? 'http://localhost:3013',
  billing: process.env.BILLING_SVC_URL ?? 'http://localhost:3008',
  audit: process.env.AUDIT_SVC_URL ?? 'http://localhost:3012',
  auth: process.env.AUTH_SVC_URL ?? 'http://localhost:3014',
  localization: process.env.LOCALIZATION_SVC_URL ?? 'http://localhost:4003',
  geo: process.env.GEO_DEVICE_URL ?? 'http://localhost:4002',
  media: process.env.MEDIA_SVC_URL ?? 'http://localhost:3016',
  suggestions: process.env.SUGGESTIONS_SVC_URL ?? 'http://localhost:3017',
  agents: process.env.MASTER_AGENTS_SVC_URL ?? 'http://localhost:3018',
  profile: process.env.PROFILE_SVC_URL ?? 'http://localhost:3019',
  llm: process.env.LLM_SVC_URL ?? 'http://localhost:3020',
};

function getTarget(path: string): { base: string; rewrite: string } | null {
  if (path === '/api/chat' || path.startsWith('/api/chat?')) return { base: SVC.chat, rewrite: '/api/v1/chat' };
  if (path.startsWith('/api/v1/library')) return { base: SVC.library, rewrite: path };
  if (path.startsWith('/api/v1/discover')) return { base: SVC.discover, rewrite: path };
  if (path.startsWith('/api/v1/search')) return { base: SVC.search, rewrite: path };
  if (path.startsWith('/api/v1/finance')) return { base: SVC.finance, rewrite: path };
  if (path.startsWith('/api/v1/travel')) return { base: SVC.travel, rewrite: path };
  if (path.startsWith('/api/v1/create') || path.startsWith('/api/v1/export')) return { base: SVC.create, rewrite: path };
  if (path.startsWith('/api/v1/memory')) return { base: SVC.memory, rewrite: path };
  if (path.startsWith('/api/v1/tasks')) return { base: SVC.chat, rewrite: path };
  if (path.startsWith('/api/v1/templates') || path.startsWith('/api/v1/connectors') || path.startsWith('/api/v1/collections')) return { base: SVC.projects, rewrite: path };
  if (path.startsWith('/api/v1/notifications')) return { base: SVC.notifications, rewrite: path };
  if (path.startsWith('/api/v1/billing')) return { base: SVC.billing, rewrite: path };
  if (path.startsWith('/api/v1/admin')) return { base: SVC.audit, rewrite: path };
  if (path.startsWith('/api/auth')) return { base: SVC.auth, rewrite: path };
  if (path.startsWith('/api/locale') || path.startsWith('/api/translations')) return { base: SVC.localization, rewrite: path };
  if (path.startsWith('/api/geo-context')) return { base: SVC.geo, rewrite: '/api/context' };
  if (path === '/api/images') return { base: SVC.media, rewrite: '/api/v1/media/images' };
  if (path === '/api/videos') return { base: SVC.media, rewrite: '/api/v1/media/videos' };
  if (path === '/api/suggestions') return { base: SVC.suggestions, rewrite: '/api/v1/suggestions' };
  if (path.startsWith('/api/v1/agents')) return { base: SVC.agents, rewrite: path };
  if (path.startsWith('/api/v1/config')) return { base: SVC.chat, rewrite: path };
  if (path.startsWith('/api/v1/providers')) return { base: SVC.llm, rewrite: path };
  if (path.startsWith('/api/v1/uploads')) return { base: SVC.chat, rewrite: path };
  if (path.startsWith('/api/v1/weather')) return { base: SVC.travel, rewrite: path };
  if (path.startsWith('/api/v1/profile')) return { base: SVC.profile, rewrite: path };
  return null;
}

async function proxyRequest(req: FastifyRequest, reply: FastifyReply, stream = false) {
  const url = new URL(req.url, `http://${req.headers.host}`);
  const path = url.pathname;
  const target = getTarget(path);
  if (!target) {
    return reply.status(404).send({ error: 'Not found' });
  }
  const fullUrl = `${target.base.replace(/\/$/, '')}${target.rewrite}${url.search}`;

  const headers: Record<string, string> = {};
  const pass = ['authorization', 'content-type', 'accept', 'x-forwarded-for', 'x-real-ip', 'user-agent', 'accept-language'];
  for (const h of pass) {
    const v = req.headers[h];
    if (v && typeof v === 'string') headers[h] = v;
  }
  if (!headers['Content-Type'] && req.method !== 'GET') headers['Content-Type'] = 'application/json';

  try {
    const method = req.method;
    let body: string | undefined;
    if (method !== 'GET' && method !== 'HEAD') {
      const b = (req as any).body;
      body = typeof b === 'string' ? b : (b != null ? JSON.stringify(b) : '');
    }
    const init: RequestInit = {
      method,
      headers,
      body,
      signal: AbortSignal.timeout(path === '/api/chat' ? 120000 : 30000),
    };
    const res = await fetch(fullUrl, init);

    const passthroughHeaders = [
      'content-type',
      'content-disposition',
      'cache-control',
      'connection',
      'set-auth-token', // better-auth bearer token для API
      'set-cookie', // better-auth session cookies
    ];
    for (const [k, v] of res.headers.entries()) {
      const l = k.toLowerCase();
      if (passthroughHeaders.includes(l)) {
        reply.header(k, v);
      }
    }
    reply.status(res.status);

    if (stream && res.body) {
      return reply.send(res.body as any);
    }
    const data = await res.text();
    const ct = res.headers.get('content-type') ?? '';
    if (ct.includes('application/json')) {
      try {
        return reply.send(JSON.parse(data));
      } catch {
        return reply.send(data);
      }
    }
    return reply.send(data);
  } catch (err: unknown) {
    req.log.error(err);
    return reply.status(503).send({ error: 'Service unavailable' });
  }
}

const app = Fastify({ logger: true });
const corsOrigin = process.env.ALLOWED_ORIGINS
  ? process.env.ALLOWED_ORIGINS.split(',')
      .map((s) => s.trim())
      .filter(Boolean)
  : true;
await app.register(cors, { origin: corsOrigin });

app.get('/health', async () => ({ status: 'ok' }));
app.get('/ready', async () => ({ status: 'ready' }));

app.post('/api/chat', async (req, reply) => proxyRequest(req, reply, true));
app.all('/api/*', async (req, reply) => proxyRequest(req, reply, false));

try {
  await app.listen({ port: PORT, host: '0.0.0.0' });
  console.log(`api-gateway listening on :${PORT}`);
} catch (err) {
  console.error(err);
  process.exit(1);
}
