import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';

import { config } from '../config';
import { resolveCartSessionId } from '../intercept/cart';
import {
  cancelPayment,
  confirmPayment,
  getOrderPayment,
  getPaymentStatus,
  initOrderPayment,
  placeMirrorOrder,
  setOrderPaymentMethod,
  startRedirectPayment,
  submitBlikPayment,
  submitCardPayment,
} from '../checkout/orderPaymentService';
import type { OrderPlacePayload } from '../checkout/orderPaymentTypes';

function requestOrigin(request: FastifyRequest): string {
  const host = String(request.headers.host ?? config.domain);
  const hostname = host.replace(/:\d+$/, '');
  const isLocal = hostname === 'localhost' || hostname.startsWith('127.');
  const protoHeader = String(request.headers['x-forwarded-proto'] ?? '')
    .split(',')[0]
    .trim();
  const proto = isLocal
    ? 'http'
    : protoHeader === 'http' || protoHeader === 'https'
      ? protoHeader
      : 'https';
  return `${proto}://${host}`;
}

async function cartSession(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<string> {
  return resolveCartSessionId(request, reply);
}

export async function registerOrderPaymentRoutes(app: FastifyInstance): Promise<void> {
  await app.register(
    async (orderApp) => {
      orderApp.get('/payment', async (request, reply) => {
        const sid = await cartSession(request, reply);
        reply.send(await getOrderPayment(sid, requestOrigin(request)));
      });

      orderApp.get('/payment/status', async (request, reply) => {
        const sid = await cartSession(request, reply);
        reply.send(await getPaymentStatus(sid, requestOrigin(request)));
      });

      orderApp.put('/payment-method', async (request, reply) => {
        const body = request.body as { paymentMethodId?: string };
        if (!body?.paymentMethodId) {
          reply.status(400).send({ ok: false, error: 'paymentMethodId required' });
          return;
        }
        const sid = await cartSession(request, reply);
        const result = await setOrderPaymentMethod(sid, body.paymentMethodId);
        reply.status(result.ok ? 200 : 400).send(result);
      });

      orderApp.post('/place', async (request, reply) => {
        const sid = await cartSession(request, reply);
        const visitorId = (request as FastifyRequest & { visitorId?: string }).visitorId;
        const result = await placeMirrorOrder(
          sid,
          (request.body ?? {}) as OrderPlacePayload,
          { visitorId },
        );
        reply.status(result.ok ? 200 : 400).send(result);
      });

      orderApp.post('/payment/init', async (request, reply) => {
        const sid = await cartSession(request, reply);
        const body = (request.body ?? {}) as {
          webhookUrl?: string;
          returnUrlSuccess?: string;
          returnUrlFailure?: string;
        };
        const result = await initOrderPayment(sid, requestOrigin(request), body);
        reply.status(result.ok === false ? 400 : 200).send(result);
      });

      orderApp.post('/payment/card', async (request, reply) => {
        const body = request.body as {
          cardNumber?: string;
          expiry?: string;
          cvc?: string;
          cardHolder?: string;
        };
        const sid = await cartSession(request, reply);
        const result = await submitCardPayment(sid, {
          cardNumber: String(body.cardNumber ?? ''),
          expiry: String(body.expiry ?? ''),
          cvc: String(body.cvc ?? ''),
          cardHolder: String(body.cardHolder ?? ''),
        });
        reply.status(result.ok ? 200 : 400).send(result);
      });

      orderApp.post('/payment/blik', async (request, reply) => {
        const body = request.body as { code?: string };
        const sid = await cartSession(request, reply);
        const result = await submitBlikPayment(sid, { code: String(body.code ?? '') });
        reply.status(result.ok ? 200 : 400).send(result);
      });

      orderApp.post('/payment/redirect', async (request, reply) => {
        const sid = await cartSession(request, reply);
        const body = (request.body ?? {}) as {
          webhookUrl?: string;
          returnUrlSuccess?: string;
          returnUrlFailure?: string;
        };
        const result = await startRedirectPayment(sid, requestOrigin(request), body);
        reply.status(result.ok === false ? 400 : 200).send(result);
      });

      orderApp.post('/payment/confirm', async (request, reply) => {
        const sid = await cartSession(request, reply);
        const body = (request.body ?? {}) as { status?: string; token?: string };
        const result = await confirmPayment(sid, body);
        reply.status(result.ok ? 200 : 400).send(result);
      });

      orderApp.post('/payment/cancel', async (request, reply) => {
        const sid = await cartSession(request, reply);
        reply.send(await cancelPayment(sid));
      });

      /** @deprecated Use POST /payment/init */
      orderApp.post('/pay', async (request, reply) => {
        const sid = await cartSession(request, reply);
        const body = (request.body ?? {}) as { webhookUrl?: string };
        const result = await initOrderPayment(sid, requestOrigin(request), body);
        reply.status(result.ok === false ? 400 : 200).send(result);
      });
    },
    { prefix: '/api/checkout/order' },
  );
}
