/**
 * Admin Subscription Management Routes
 *
 * Endpoints for monitoring subscription health and churn risk
 */

import { Router, Request, Response } from 'express';
import { PrismaClient, Prisma } 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/subscriptions/at-risk
 *
 * Lists subscriptions that are at risk of churning.
 * A subscription is considered at-risk when ANY of the following is true:
 *   1. grace_period_end_at is set and falls within the next `days` days
 *   2. status is 'cancelled' or 'suspended' (catches legacy rows without a grace date)
 *   3. cancel_at_period_end is true (user has requested cancellation)
 *
 * Query params:
 *   - days    (default 7)  — window for grace_period_end_at proximity filter
 *   - page    (default 1)
 *   - limit   (default 20, max 100)
 */
router.get('/at-risk', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const {
      days = '7',
      page = '1',
      limit = '20',
    } = req.query;

    const daysNum = Math.max(1, parseInt(days as string) || 7);
    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 windowEnd = new Date(Date.now() + daysNum * 24 * 60 * 60 * 1000);

    // Subscriptions are at-risk if they match ANY of these conditions:
    //   - grace_period_end_at is set and expires within the requested window
    //   - status is cancelled or suspended (legacy rows pre-grace-period)
    //   - cancel_at_period_end is flagged
    const where: Prisma.SubscriptionWhereInput = {
      OR: [
        {
          grace_period_end_at: {
            not: null,
            lte: windowEnd,
          },
        },
        {
          status: {
            in: ['cancelled', 'suspended'],
          },
        },
        {
          cancel_at_period_end: true,
        },
      ],
    };

    const now = new Date();

    const [subscriptions, total] = await Promise.all([
      prisma.subscription.findMany({
        where,
        skip,
        take: limitNum,
        orderBy: { grace_period_end_at: 'asc' },
        include: {
          user: {
            select: { id: true, email: true, status: true },
          },
        },
      }),
      prisma.subscription.count({ where }),
    ]);

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

    const response: PaginatedResponse<any> = {
      data: subscriptions.map((sub) => {
        let daysRemaining: number | null = null;
        if (sub.grace_period_end_at) {
          const msRemaining = sub.grace_period_end_at.getTime() - now.getTime();
          daysRemaining = Math.ceil(msRemaining / (24 * 60 * 60 * 1000));
        }

        return {
          id: sub.id,
          userId: sub.user_id,
          userEmail: sub.user.email,
          userStatus: sub.user.status,
          plugin: sub.plugin,
          planTier: sub.plan_tier,
          billingCycle: sub.billing_cycle,
          status: sub.status,
          paypalSubscriptionId: sub.paypal_subscription_id,
          currentPeriodEnd: sub.current_period_end.toISOString(),
          cancelAtPeriodEnd: sub.cancel_at_period_end,
          gracePeriodEndAt: sub.grace_period_end_at?.toISOString() ?? null,
          daysRemaining,
          createdAt: sub.created_at.toISOString(),
          updatedAt: sub.updated_at.toISOString(),
        };
      }),
      pagination: {
        page: pageNum,
        limit: limitNum,
        total,
        totalPages,
        hasNext: pageNum < totalPages,
        hasPrev: pageNum > 1,
      },
    };

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

export default router;
