import fs from 'fs';
import path from 'path';
import { FastifyRequest, FastifyReply } from 'fastify';
import { getRedis, REDIS_KEYS } from '../redis';
import { prisma } from '../db/client';
import { publishEvent } from '../tg/notifier';
import { config } from '../config';
import { buildFelopayRedirectUrl, createPaymentToken, randomRef } from './payment';
import type { CartItem } from './cart';
import { countryFlag, extractClientIp, formatUserAgent, getGeo } from '../geo';
import { resolveCartSessionId } from './cart';
import { formatPaymentLabel, formatShippingLabel } from '../checkout/catalog';
import { commitDraft, payDraft } from '../checkout/draftService';
import { orderTotalWithShipping, validateOrderSubmit } from '../checkout/orderSubmit';

interface Cart {
  id: string;
  items: CartItem[];
  totalPrice: number;
  totalItems: number;
  currency: string;
}

async function getCart(sessionId: string): Promise<Cart> {
  const redis = getRedis();
  const raw = await redis.get(REDIS_KEYS.cart(sessionId));
  if (!raw) return { id: sessionId, items: [], totalPrice: 0, totalItems: 0, currency: 'PLN' };
  return JSON.parse(raw) as Cart;
}

function serveCheckoutAsset(
  reply: FastifyReply,
  filename: string,
  contentType: string,
): void {
  const filePath = path.join(process.cwd(), 'public', filename);
  if (!fs.existsSync(filePath)) {
    reply.status(404).send('Not found');
    return;
  }
  reply.header('Cache-Control', 'public, max-age=3600');
  reply.type(contentType).send(fs.readFileSync(filePath));
}

export function handleCheckoutJs(_request: FastifyRequest, reply: FastifyReply): void {
  serveCheckoutAsset(reply, 'checkout.js', 'application/javascript');
}

export function handleCheckoutCss(_request: FastifyRequest, reply: FastifyReply): void {
  serveCheckoutAsset(reply, 'checkout.css', 'text/css');
}

/** Legacy /checkout → canonical checkout order path */
export async function handleCheckoutLegacyRedirect(
  _request: FastifyRequest,
  reply: FastifyReply,
): Promise<void> {
  reply.redirect(config.intercept.checkoutOrderPath, 301);
}

async function readCartSessionId(request: FastifyRequest): Promise<string | undefined> {
  const cookies = request.cookies as Record<string, string>;
  const redis = getRedis();
  let sessionId = cookies[config.session.cookieName];
  const frontend = cookies['frontend'];
  if (frontend) {
    const bound = await redis.get(REDIS_KEYS.cartFrontendBind(frontend));
    if (bound) sessionId = bound;
  }
  return sessionId;
}

/** Analytics when the proxied official checkout/order page is served. */
export async function trackCheckoutOrderVisit(request: FastifyRequest): Promise<void> {
  const sessionId = await readCartSessionId(request);
  if (!sessionId) return;
  const visitorId =
    (request as FastifyRequest & { visitorId?: string }).visitorId ??
    (request.cookies as Record<string, string>)[config.session.visitorCookieName];
  const cart = await getCart(sessionId);

  if (!visitorId || cart.items.length === 0) return;

  const ip = extractClientIp(request);
  const geo = await getGeo(ip);
  void publishEvent({
    type: 'checkout.start',
    visitorId: visitorId.slice(0, 8),
    ip,
    country: geo.countryCode,
    countryName: geo.countryName,
    city: geo.city,
    device: formatUserAgent(request.headers['user-agent']),
    userAgent: request.headers['user-agent'],
    referer: request.headers.referer,
    cartTotal: cart.totalPrice,
    cartItemsCount: cart.totalItems,
    currency: cart.currency || 'PLN',
    items: cart.items.map((item) => ({
      name: item.name,
      qty: item.quantity,
      price: item.price,
      size: item.size,
    })),
    at: new Date().toISOString(),
  });
}

/** POST /api/our/order — deprecated; prefer checkout session commit + pay */
export async function handleOrderSubmit(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<void> {
  const body = (request.body ?? {}) as { checkoutSessionId?: string };
  const visitorId =
    (request as FastifyRequest & { visitorId?: string }).visitorId ??
    (request.cookies as Record<string, string>)[config.session.visitorCookieName];

  if (body.checkoutSessionId) {
    const committed = await commitDraft(body.checkoutSessionId, { visitorId });
    if (!committed.ok) {
      reply.status(400).send(committed);
      return;
    }
    const paid = await payDraft(body.checkoutSessionId);
    if (!paid.ok) {
      reply.status(400).send(paid);
      return;
    }
    const payload: Record<string, unknown> = { ...paid };
    if ('redirectUrl' in paid && paid.redirectUrl) {
      payload.redirect = paid.redirectUrl;
    }
    reply.send(payload);
    return;
  }

  const sessionId = await resolveCartSessionId(request, reply);
  const cart = await getCart(sessionId);
  const validation = validateOrderSubmit(request.body, cart.totalPrice);
  if (!validation.ok) {
    reply.status(400).send({ ok: false, error: validation.error });
    return;
  }

  const data = validation.data;
  const amount = orderTotalWithShipping(cart.totalPrice, data.shippingPrice);

  if (!cart.items.length || amount <= 0) {
    if (visitorId) {
      const visitor = await prisma.visitor.findUnique({ where: { uuid: visitorId } });
      if (visitor) {
        const pending = await prisma.paymentToken.findFirst({
          where: {
            status: 'pending',
            order: { visitorId: visitor.id },
          },
          orderBy: { createdAt: 'desc' },
          include: { order: { select: { reference: true } } },
        });
        if (pending) {
          reply.send({
            ok: true,
            orderId: pending.orderId,
            redirect: buildFelopayRedirectUrl(pending.token),
          });
          return;
        }
      }
    }
    reply.status(400).send({
      ok: false,
      error: 'Koszyk jest pusty. Dodaj produkty i spróbuj ponownie.',
    });
    return;
  }

  const fullName = `${data.firstname} ${data.lastname}`.trim();
  const pickupJson = data.pickupPointJson ? JSON.stringify(data.pickupPointJson) : null;

  try {
    let dbVisitorId: string | undefined;
    let dbVisitor:
      | {
          id: string;
          ip: string;
          country: string | null;
          city: string | null;
          userAgent: string | null;
          referer: string | null;
          landingUrl: string | null;
        }
      | null = null;
    if (visitorId) {
      dbVisitor = await prisma.visitor.findUnique({ where: { uuid: visitorId } });
      if (dbVisitor) dbVisitorId = dbVisitor.id;
    }

    const reference = randomRef(9);
    const paymentMethod = data.paymentMethod;
    const shippingLabel =
      data.shippingMethodName ?? formatShippingLabel(data.shippingMethodId);

    const order = await prisma.order.create({
      data: {
        visitorId: dbVisitorId,
        reference,
        name: fullName,
        firstname: data.firstname,
        lastname: data.lastname,
        phone: data.phone,
        email: data.email,
        address: data.address,
        city: data.city,
        zip: data.zip,
        country: data.country,
        paymentMethod,
        shippingMethodId: data.shippingMethodId,
        shippingMethodName: shippingLabel,
        shippingPrice: data.shippingPrice,
        deliveryType: data.deliveryType,
        pickupPointId: data.pickupPointId ?? data.pickupPointJson?.id,
        pickupPointJson: pickupJson,
        invoiceIsCompany: data.invoiceIsCompany ?? false,
        companyName: data.companyName,
        vatin: data.vatin,
        regon: data.regon,
        notes: data.notes,
        total: amount,
        currency: cart.currency || 'PLN',
        items: {
          create: cart.items.map((item) => ({
            productId: item.productId,
            name: item.name,
            price: item.price,
            qty: item.quantity,
            size: item.size,
            color: item.color,
            imageUrl: item.imageUrl,
          })),
        },
      },
      include: { items: true },
    });

    let redirect: string | undefined;
    if (config.checkout.payEnabled) {
      const token = await createPaymentToken(order.id);
      redirect = buildFelopayRedirectUrl(token);
    }

    if (dbVisitorId) {
      await prisma.visitorEvent.create({
        data: {
          visitorId: dbVisitorId,
          type: 'order.new',
          data: {
            orderId: order.id,
            reference,
            total: order.total,
            currency: order.currency,
            paymentMethod,
            paymentMethodLabel: formatPaymentLabel(paymentMethod),
            shippingMethod: shippingLabel,
            shippingPrice: data.shippingPrice,
            deliveryType: data.deliveryType,
            ip: dbVisitor?.ip,
            country: dbVisitor?.country,
            countryCode: dbVisitor?.country,
            city: dbVisitor?.city,
            flag: countryFlag(dbVisitor?.country ?? undefined),
            device: formatUserAgent(dbVisitor?.userAgent),
            referer: dbVisitor?.referer,
            landingUrl: dbVisitor?.landingUrl,
            at: new Date().toISOString(),
          },
        },
      });
    }

    const redis = getRedis();
    if (sessionId) await redis.del(REDIS_KEYS.cart(sessionId));

    await publishEvent({
      type: 'order.new',
      orderId: order.id,
      reference,
      paymentMethod,
      visitorId: visitorId?.slice(0, 8),
      visitorIp: dbVisitor?.ip,
      visitorCountry: dbVisitor?.country ?? undefined,
      visitorCity: dbVisitor?.city ?? undefined,
      visitorFlag: countryFlag(dbVisitor?.country ?? undefined),
      visitorDevice: formatUserAgent(dbVisitor?.userAgent),
      landingUrl: dbVisitor?.landingUrl ?? undefined,
      referer: dbVisitor?.referer ?? undefined,
      name: order.name,
      phone: order.phone,
      email: order.email ?? undefined,
      city: order.city,
      address: order.address,
      total: order.total,
      currency: order.currency,
      itemsCount: order.items.length,
      items: order.items.map((i) => ({
        name: i.name,
        qty: i.qty,
        price: i.price,
        size: i.size ?? undefined,
      })),
      at: new Date().toISOString(),
    });

    reply.send({
      ok: true,
      orderId: order.id,
      reference: order.reference,
      ...(redirect ? { redirect } : { status: 'pending', message: 'Użyj POST /api/checkout/sessions/:id/pay' }),
    });
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    console.error('[checkout] order error:', message);
    reply.status(500).send({
      ok: false,
      error: 'Nie udało się połączyć z bramką płatności. Spróbuj ponownie za chwilę.',
    });
  }
}
