/**
 * Finance Service
 * Handles payments, ledgers, rate models, and invoicing
 */

import Fastify, { type FastifyRequest, type FastifyReply } from 'fastify';
import fastifySwagger from '@fastify/swagger';
import fastifySwaggerUI from '@fastify/swagger-ui';
import {
  errorHandler,
  createLogger,
  registerSecurityPlugins,
  addCorrelationId,
  addRequestLogging,
  getEnv,
  createBodySchema,
  authenticateJWT,
  requireRole,
} from '@the-order/shared';
import { CreateLedgerEntrySchema, CreatePaymentSchema } from '@the-order/schemas';
import { healthCheck as dbHealthCheck, getPool, createLedgerEntry, createPayment, updatePaymentStatus } from '@the-order/database';
import { StripePaymentGateway } from '@the-order/payment-gateway';

const logger = createLogger('finance-service');

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const server: any = Fastify({
  logger: logger as any,
  requestIdLogLabel: 'requestId',
  disableRequestLogging: false,
});

// Initialize database pool
const env = getEnv();
if (env.DATABASE_URL) {
  getPool({ connectionString: env.DATABASE_URL });
}

// Initialize payment gateway
let paymentGateway: StripePaymentGateway | null = null;
try {
  if (env.PAYMENT_GATEWAY_API_KEY) {
    paymentGateway = new StripePaymentGateway();
  }
} catch (error) {
  logger.warn({ err: error }, 'Payment gateway not configured');
}

// Initialize server
async function initializeServer(): Promise<void> {
  // Register Swagger
  const swaggerUrl = env.SWAGGER_SERVER_URL || (env.NODE_ENV === 'development' ? 'http://localhost:4003' : undefined);
  if (!swaggerUrl) {
    logger.warn('SWAGGER_SERVER_URL not set, Swagger documentation will not be available');
  } else {
    await server.register(fastifySwagger, {
      openapi: {
        info: {
          title: 'Finance Service API',
          description: 'Payments, ledgers, rate models, and invoicing',
          version: '1.0.0',
        },
        servers: [
          {
            url: swaggerUrl,
            description: env.NODE_ENV || 'Development server',
          },
        ],
      },
    });

    await server.register(fastifySwaggerUI, {
      routePrefix: '/docs',
    });
  }

  await registerSecurityPlugins(server as any);
  addCorrelationId(server as any);
  addRequestLogging(server as any);
  server.setErrorHandler(errorHandler as any);
}

// Health check
server.get(
  '/health',
  {
    schema: {
      description: 'Health check endpoint',
      tags: ['health'],
      response: {
        200: {
          type: 'object',
          properties: {
            status: { type: 'string' },
            service: { type: 'string' },
            database: { type: 'string' },
          },
        },
      },
    },
  },
  async () => {
    const dbHealthy = await dbHealthCheck();
    return {
      status: dbHealthy ? 'ok' : 'degraded',
      service: 'finance',
      database: dbHealthy ? 'connected' : 'disconnected',
    };
  }
);

// Ledger operations
server.post(
  '/ledger/entry',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any, requireRole('admin', 'accountant', 'finance') as any],
    schema: {
      ...createBodySchema(CreateLedgerEntrySchema),
      description: 'Create a ledger entry',
      tags: ['ledger'],
      response: {
        201: {
          type: 'object',
          properties: {
            entry: {
              type: 'object',
            },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, reply: FastifyReply) => {
    const body = request.body as {
      accountId: string;
      type: 'debit' | 'credit';
      amount: number;
      currency: string;
      description?: string;
      reference?: string;
    };

    // Save to database
    const entry = await createLedgerEntry({
      account_id: body.accountId,
      type: body.type,
      amount: body.amount,
      currency: body.currency,
      description: body.description,
      reference: body.reference,
    });

    return reply.status(201).send({ entry });
  }
);

// Payment processing
server.post(
  '/payments',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any],
    schema: {
      ...createBodySchema(CreatePaymentSchema),
      description: 'Process a payment',
      tags: ['payments'],
      response: {
        201: {
          type: 'object',
          properties: {
            payment: {
              type: 'object',
            },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, reply: FastifyReply) => {
    const body = request.body as {
      amount: number;
      currency: string;
      paymentMethod: string;
      metadata?: Record<string, string>;
    };

    // Create payment record
    const payment = await createPayment({
      amount: body.amount,
      currency: body.currency,
      status: 'pending',
      payment_method: body.paymentMethod,
    });

    // Process payment through gateway if available
    if (paymentGateway) {
      try {
        const result = await paymentGateway.processPayment(
          body.amount,
          body.currency,
          body.paymentMethod,
          {
            payment_id: payment.id,
            ...body.metadata,
          }
        );

        // Update payment status
        const updatedPayment = await updatePaymentStatus(
          payment.id,
          result.status,
          result.transactionId,
          result.gatewayResponse
        );

        return reply.status(201).send({ payment: updatedPayment });
      } catch (error) {
        logger.error({ err: error, paymentId: payment.id }, 'Payment processing failed');
        await updatePaymentStatus(payment.id, 'failed', undefined, { error: String(error) });
        throw error;
      }
    } else {
      // No payment gateway configured - return pending status
      return reply.status(201).send({ payment });
    }
  }
);

// Start server
const start = async () => {
  try {
    await initializeServer();
    const env = getEnv();
    const port = env.PORT || 4003;
    await server.listen({ port, host: '0.0.0.0' });
    logger.info({ port }, 'Finance service listening');
  } catch (err) {
    logger.error({ err }, 'Failed to start server');
    process.exit(1);
  }
};

start();

