/**
 * Admin Payment Dispute Management Routes
 *
 * Endpoints for viewing chargeback/dispute records (legal compliance)
 */

import { Router, Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import { authenticateAdmin } from '../../middleware/auth';
import { logger } from '../../utils/logger';
import { PaginatedResponse } from '../../types';

const router = Router();
const prisma = new PrismaClient();

/**
 * GET /v1/admin/disputes
 * List all payment disputes with pagination and filtering
 *
 * Query params:
 *   page       - page number (default 1)
 *   limit      - page size (default 20, max 100)
 *   status     - filter by dispute status (open|under_review|won|lost|closed)
 *   from       - filter opened_at >= (ISO date string)
 *   to         - filter opened_at <= (ISO date string)
 *   sortOrder  - asc|desc (default desc)
 *   orphan     - true → only disputes with no linked payment; false → only linked; absent → all
 */
router.get('/', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const {
      page = '1',
      limit = '20',
      status,
      from,
      to,
      sortOrder = 'desc',
      orphan,
    } = req.query;

    const pageNum = Math.max(1, parseInt(page as string));
    const limitNum = Math.min(100, Math.max(1, parseInt(limit as string)));
    const skip = (pageNum - 1) * limitNum;

    const where: any = {};

    if (status) {
      where.status = status as string;
    }

    if (from || to) {
      where.opened_at = {};
      if (from) {
        where.opened_at.gte = new Date(from as string);
      }
      if (to) {
        where.opened_at.lte = new Date(to as string);
      }
    }

    if (orphan === 'true') {
      where.payment_id = null;
    } else if (orphan === 'false') {
      where.payment_id = { not: null };
    }

    const orderBy = { opened_at: sortOrder === 'asc' ? ('asc' as const) : ('desc' as const) };

    const [disputes, total] = await Promise.all([
      prisma.paymentDispute.findMany({
        where,
        skip,
        take: limitNum,
        orderBy,
        include: {
          payment: {
            select: {
              id: true,
              paypal_payment_id: true,
              amount: true,
              currency: true,
              status: true,
              user_id: true,
              user: {
                select: {
                  id: true,
                  email: true,
                  status: true,
                },
              },
            },
          },
        },
      }),
      prisma.paymentDispute.count({ where }),
    ]);

    const totalPages = Math.ceil(total / limitNum);

    const response: PaginatedResponse<any> = {
      data: disputes.map((d) => ({
        id: d.id,
        paypalDisputeId: d.paypal_dispute_id,
        paypalSaleId: (d as any).paypal_sale_id ?? null,
        paymentId: d.payment_id,
        orphan: d.payment_id === null,
        payment: d.payment
          ? {
              id: d.payment.id,
              paypalPaymentId: d.payment.paypal_payment_id,
              amount: d.payment.amount.toString(),
              currency: d.payment.currency,
              status: d.payment.status,
            }
          : null,
        user: d.payment
          ? {
              id: d.payment.user.id,
              email: d.payment.user.email,
              status: d.payment.user.status,
            }
          : null,
        reason: d.reason,
        status: d.status,
        amount: d.amount.toString(),
        currency: d.currency,
        openedAt: d.opened_at.toISOString(),
        resolvedAt: d.resolved_at?.toISOString() ?? null,
        notes: d.notes ?? null,
        createdAt: d.created_at.toISOString(),
      })),
      pagination: {
        page: pageNum,
        limit: limitNum,
        total,
        totalPages,
        hasNext: pageNum < totalPages,
        hasPrev: pageNum > 1,
      },
    };

    res.json(response);
  } catch (error) {
    logger.error('Error fetching disputes list', { error, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch disputes',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/disputes/:id
 * Get detailed information about a specific dispute, including raw webhook payload
 */
router.get('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const dispute = await prisma.paymentDispute.findUnique({
      where: { id },
      include: {
        payment: {
          select: {
            id: true,
            paypal_payment_id: true,
            amount: true,
            currency: true,
            status: true,
            type: true,
            created_at: true,
            user_id: true,
            user: {
              select: {
                id: true,
                email: true,
                status: true,
                subscriptions: {
                  select: {
                    plan_tier: true,
                    status: true,
                    billing_cycle: true,
                  },
                },
              },
            },
            subscription: {
              select: {
                id: true,
                plan_tier: true,
                billing_cycle: true,
                status: true,
              },
            },
          },
        },
      },
    });

    if (!dispute) {
      res.status(404).json({
        error: true,
        code: 'DISPUTE_NOT_FOUND',
        message: 'Dispute not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    res.json({
      id: dispute.id,
      paypalDisputeId: dispute.paypal_dispute_id,
      paypalSaleId: (dispute as any).paypal_sale_id ?? null,
      paymentId: dispute.payment_id,
      orphan: dispute.payment_id === null,
      payment: dispute.payment
        ? {
            id: dispute.payment.id,
            paypalPaymentId: dispute.payment.paypal_payment_id,
            amount: dispute.payment.amount.toString(),
            currency: dispute.payment.currency,
            status: dispute.payment.status,
            type: dispute.payment.type,
            createdAt: dispute.payment.created_at.toISOString(),
            subscription: dispute.payment.subscription
              ? {
                  id: dispute.payment.subscription.id,
                  planTier: dispute.payment.subscription.plan_tier,
                  billingCycle: dispute.payment.subscription.billing_cycle,
                  status: dispute.payment.subscription.status,
                }
              : null,
          }
        : null,
      user: dispute.payment
        ? {
            id: dispute.payment.user.id,
            email: dispute.payment.user.email,
            status: dispute.payment.user.status,
            subscription: dispute.payment.user.subscriptions[0]
              ? {
                  plan: dispute.payment.user.subscriptions[0].plan_tier,
                  status: dispute.payment.user.subscriptions[0].status,
                  billingCycle: dispute.payment.user.subscriptions[0].billing_cycle,
                }
              : null,
          }
        : null,
      reason: dispute.reason,
      status: dispute.status,
      amount: dispute.amount.toString(),
      currency: dispute.currency,
      notes: dispute.notes ?? null,
      rawWebhookPayload: dispute.raw_webhook_payload,
      openedAt: dispute.opened_at.toISOString(),
      resolvedAt: dispute.resolved_at?.toISOString() ?? null,
      createdAt: dispute.created_at.toISOString(),
      updatedAt: dispute.updated_at.toISOString(),
    });
  } catch (error) {
    logger.error('Error fetching dispute details', {
      error,
      disputeId: req.params.id,
      adminId: req.admin?.id,
    });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch dispute details',
      timestamp: new Date().toISOString(),
    });
  }
});

export default router;
