/**
 * Admin Tiers Routes
 *
 * CRUD endpoints for managing subscription tiers.
 * All routes require admin authentication.
 *
 * Base path: /v1/admin/tiers
 */

import { Router, Request, Response } from 'express';
import { z } from 'zod';
import { PrismaClient } from '@prisma/client';
import { authenticateAdmin } from '../../middleware/auth';
import { errorResponse, successResponse } from '../../utils/errorHandler';
import { tierService } from '../../services/tierService';
import { logger } from '../../utils/logger';
import { createPlansForTier, syncTierPricing, deactivatePlansForTier, activatePayPalPlan } from '../../services/paypalPlanService';
import { getPayPalConfig } from '../../config';

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

/**
 * Zod schema for creating a tier
 */
const createTierSchema = z.object({
  slug: z.string().min(1).max(50).regex(/^[a-z0-9_-]+$/),
  name: z.string().min(1).max(100),
  description: z.string().optional(),
  monthly_price: z.number().min(0),
  annual_price: z.number().min(0),
  credit_allocation: z.number().int().min(0),
  rate_limit: z.number().int().min(0),
  allowed_models: z.array(z.string()).default([]),
  features: z.array(z.string()).default([]),
  plugin: z.string().min(1).max(30).default('translate'),
  plugin_limits: z.record(z.unknown()).default({}),
  paypal_plan_monthly: z.string().optional(),
  paypal_plan_annual: z.string().optional(),
  display_order: z.number().int().default(0),
  is_active: z.boolean().default(true),
});

/**
 * Update schema: all fields optional
 */
const updateTierSchema = createTierSchema.partial();

/**
 * Reorder schema
 */
const reorderSchema = z.object({
  tiers: z.array(
    z.object({
      id: z.string().uuid(),
      display_order: z.number().int().min(0),
    })
  ),
});

/**
 * GET /
 * List all tiers (ordered by display_order)
 */
router.get('/', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const plugin = req.query.plugin as string | undefined;
    const where = plugin ? { plugin } : {};
    const tiers = await prisma.subscriptionTier.findMany({
      where,
      orderBy: { display_order: 'asc' },
    });

    return res.status(200).json(successResponse({ tiers }));
  } catch (error) {
    logger.error('Failed to list tiers', { error });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to list tiers'));
  }
});

/**
 * GET /:id
 * Get a single tier
 */
router.get('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const tier = await prisma.subscriptionTier.findUnique({
      where: { id },
    });

    if (!tier) {
      return res.status(404).json(errorResponse('NOT_FOUND', 'Tier not found'));
    }

    return res.status(200).json(successResponse({ tier }));
  } catch (error) {
    logger.error('Failed to get tier', { error, id: req.params.id });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to get tier'));
  }
});

/**
 * POST /
 * Create a new tier
 */
router.post('/', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const validation = createTierSchema.safeParse(req.body);
    if (!validation.success) {
      return res.status(400).json(errorResponse('VALIDATION_ERROR', validation.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join('; ')));
    }

    const data = validation.data;

    // Check slug uniqueness within plugin
    const existing = await prisma.subscriptionTier.findUnique({
      where: { plugin_slug: { plugin: data.plugin, slug: data.slug } },
    });

    if (existing) {
      return res.status(409).json(errorResponse('SLUG_EXISTS', `A tier with slug '${data.slug}' already exists for plugin '${data.plugin}'`));
    }

    let tier = await prisma.subscriptionTier.create({
      data: {
        slug: data.slug,
        name: data.name,
        description: data.description,
        monthly_price: data.monthly_price,
        annual_price: data.annual_price,
        credit_allocation: data.credit_allocation,
        rate_limit: data.rate_limit,
        allowed_models: data.allowed_models,
        features: data.features,
        plugin: data.plugin,
        plugin_limits: data.plugin_limits as any,
        paypal_plan_monthly: data.paypal_plan_monthly,
        paypal_plan_annual: data.paypal_plan_annual,
        display_order: data.display_order,
        is_active: data.is_active,
      },
    });

    // Auto-create PayPal billing plans if not manually supplied
    if (!data.paypal_plan_monthly && !data.paypal_plan_annual) {
      try {
        const paypalConfig = getPayPalConfig();
        const productId = paypalConfig.productId;
        if (productId && Number(tier.monthly_price) > 0 && Number(tier.annual_price) > 0) {
          const { monthlyPlanId, annualPlanId } = await createPlansForTier(
            tier.name,
            Number(tier.monthly_price),
            Number(tier.annual_price),
            productId
          );

          // Update tier with auto-generated plan IDs
          tier = await prisma.subscriptionTier.update({
            where: { id: tier.id },
            data: {
              paypal_plan_monthly: monthlyPlanId,
              paypal_plan_annual: annualPlanId,
            },
          });

          logger.info('PayPal plans auto-created for new tier', {
            tierId: tier.id,
            monthlyPlanId,
            annualPlanId,
          });
        }
      } catch (paypalError) {
        // Don't fail tier creation if PayPal plan creation fails
        // Admin can manually retry or set plan IDs later
        logger.error('Failed to auto-create PayPal plans for tier', {
          tierId: tier.id,
          error: paypalError instanceof Error ? paypalError.message : 'Unknown error',
        });
      }
    }

    // Clear cache so subsequent reads reflect new tier
    tierService.clearCache();

    logger.info('Tier created', {
      adminId: req.admin?.id,
      tierId: tier.id,
      slug: tier.slug,
    });

    return res.status(201).json(successResponse({ tier }));
  } catch (error) {
    logger.error('Failed to create tier', { error });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to create tier'));
  }
});

/**
 * PUT /:id
 * Update a tier (partial update)
 */
router.put('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const validation = updateTierSchema.safeParse(req.body);
    if (!validation.success) {
      return res.status(400).json(errorResponse('VALIDATION_ERROR', validation.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join('; ')));
    }

    const data = validation.data;

    // Verify tier exists
    const existing = await prisma.subscriptionTier.findUnique({
      where: { id },
    });

    if (!existing) {
      return res.status(404).json(errorResponse('NOT_FOUND', 'Tier not found'));
    }

    // If slug is being changed, check uniqueness within plugin
    if (data.slug && data.slug !== existing.slug) {
      const plugin = data.plugin || existing.plugin;
      const slugConflict = await prisma.subscriptionTier.findUnique({
        where: { plugin_slug: { plugin, slug: data.slug } },
      });
      if (slugConflict) {
        return res.status(409).json(errorResponse('SLUG_EXISTS', `A tier with slug '${data.slug}' already exists for plugin '${plugin}'`));
      }
    }

    let tier = await prisma.subscriptionTier.update({
      where: { id },
      data: data as any,
    });

    // Sync PayPal plan pricing if prices changed
    try {
      const paypalConfig = getPayPalConfig();
      const productId = paypalConfig.productId;
      if (productId) {
        const planUpdates = await syncTierPricing(
          existing,
          data.monthly_price !== undefined ? Number(data.monthly_price) : undefined,
          data.annual_price !== undefined ? Number(data.annual_price) : undefined,
          productId
        );

        // If new plans were created (tier didn't have plan IDs before), save them
        if (planUpdates.paypal_plan_monthly || planUpdates.paypal_plan_annual) {
          tier = await prisma.subscriptionTier.update({
            where: { id: tier.id },
            data: planUpdates,
          });
          // Merge into response object
          Object.assign(tier, planUpdates);
        }
      }
    } catch (paypalError) {
      logger.error('Failed to sync PayPal plan pricing', {
        tierId: tier.id,
        error: paypalError instanceof Error ? paypalError.message : 'Unknown error',
      });
    }

    // Sync PayPal plan active status if is_active changed
    if (data.is_active !== undefined && data.is_active !== existing.is_active) {
      try {
        if (data.is_active) {
          // Reactivate plans
          if (tier.paypal_plan_monthly) await activatePayPalPlan(tier.paypal_plan_monthly);
          if (tier.paypal_plan_annual) await activatePayPalPlan(tier.paypal_plan_annual);
        } else {
          // Deactivate plans
          await deactivatePlansForTier(
            tier.paypal_plan_monthly,
            tier.paypal_plan_annual
          );
        }
      } catch (paypalError) {
        logger.error('Failed to sync PayPal plan active status', {
          tierId: tier.id,
          isActive: data.is_active,
          error: paypalError instanceof Error ? paypalError.message : 'Unknown error',
        });
      }
    }

    tierService.clearCache();

    logger.info('Tier updated', {
      adminId: req.admin?.id,
      tierId: tier.id,
      slug: tier.slug,
    });

    return res.status(200).json(successResponse({ tier }));
  } catch (error) {
    logger.error('Failed to update tier', { error, id: req.params.id });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to update tier'));
  }
});

/**
 * DELETE /:id
 * Delete a tier (409 if active subscriptions/licenses reference its slug)
 */
router.delete('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const tier = await prisma.subscriptionTier.findUnique({
      where: { id },
    });

    if (!tier) {
      return res.status(404).json(errorResponse('NOT_FOUND', 'Tier not found'));
    }

    // Check for active subscriptions referencing this tier slug
    const activeSubscriptions = await prisma.subscription.count({
      where: { plan_tier: tier.slug, status: 'active' },
    });

    if (activeSubscriptions > 0) {
      return res.status(409).json(
        errorResponse(
          'TIER_IN_USE',
          `Cannot delete tier '${tier.slug}': ${activeSubscriptions} active subscription(s) reference it`
        )
      );
    }

    // Check for active licenses referencing this tier slug
    const activeLicenses = await prisma.license.count({
      where: { plan_tier: tier.slug, status: 'active' },
    });

    if (activeLicenses > 0) {
      return res.status(409).json(
        errorResponse(
          'TIER_IN_USE',
          `Cannot delete tier '${tier.slug}': ${activeLicenses} active license(s) reference it`
        )
      );
    }

    // Deactivate PayPal plans before deleting tier
    try {
      await deactivatePlansForTier(
        tier.paypal_plan_monthly,
        tier.paypal_plan_annual
      );
    } catch (paypalError) {
      logger.error('Failed to deactivate PayPal plans for deleted tier', {
        tierId: tier.id,
        error: paypalError instanceof Error ? paypalError.message : 'Unknown error',
      });
      // Continue with deletion even if PayPal deactivation fails
    }

    await prisma.subscriptionTier.delete({
      where: { id },
    });

    tierService.clearCache();

    logger.info('Tier deleted', {
      adminId: req.admin?.id,
      tierId: id,
      slug: tier.slug,
    });

    return res.status(200).json(successResponse({ deleted: true }));
  } catch (error) {
    logger.error('Failed to delete tier', { error, id: req.params.id });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to delete tier'));
  }
});

/**
 * PATCH /reorder
 * Batch update display_order for tiers
 */
router.patch('/reorder', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const validation = reorderSchema.safeParse(req.body);
    if (!validation.success) {
      return res.status(400).json(errorResponse('VALIDATION_ERROR', validation.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join('; ')));
    }

    const { tiers } = validation.data;

    await prisma.$transaction(
      tiers.map((t) =>
        prisma.subscriptionTier.update({
          where: { id: t.id },
          data: { display_order: t.display_order },
        })
      )
    );

    tierService.clearCache();

    logger.info('Tiers reordered', {
      adminId: req.admin?.id,
      count: tiers.length,
    });

    return res.status(200).json(successResponse({ reordered: true }));
  } catch (error) {
    logger.error('Failed to reorder tiers', { error });
    return res.status(500).json(errorResponse('INTERNAL_ERROR', 'Failed to reorder tiers'));
  }
});

export default router;
