/**
 * Subscription Plan Controller
 * API endpoints for subscription plan management
 *
 * @module BillingUsage
 * @prefix /api/v1/billing/plans
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  SubscriptionPlanService,
  CreateSubscriptionPlanDto,
  UpdateSubscriptionPlanDto,
  CreatePlanFeatureDto,
  CreatePlanLimitDto,
} from '../services/subscription-plan.service';

const router = Router();
const planService = new SubscriptionPlanService();

/**
 * GET /api/v1/billing/plans
 * List all subscription plans
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { planType, isActive, isPublic, search } = req.query;

    const plans = await planService.findAll({
      planType: planType as any,
      isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
      isPublic: isPublic === 'true' ? true : isPublic === 'false' ? false : undefined,
      search: search as string,
    });

    return res.json({
      success: true,
      data: plans,
      count: plans.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/plans/public
 * List public subscription plans (for pricing page)
 */
router.get('/public', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const plans = await planService.findPublicPlans();

    return res.json({
      success: true,
      data: plans,
      count: plans.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/plans/compare
 * Compare multiple plans
 */
router.get('/compare', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { ids } = req.query;

    if (!ids || typeof ids !== 'string') {
      return res.status(400).json({ error: 'ids query parameter required (comma-separated)' });
    }

    const planIds = ids.split(',');
    const comparison = await planService.comparePlans(planIds);

    return res.json({
      success: true,
      data: comparison,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/plans/:id
 * Get plan by ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const plan = await planService.findById(req.params.id);
    if (!plan) {
      return res.status(404).json({ error: 'Plan not found' });
    }

    return res.json({ success: true, data: plan });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/plans/:id/details
 * Get plan with features and limits
 */
router.get('/:id/details', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const details = await planService.getPlanWithDetails(req.params.id);
    if (!details) {
      return res.status(404).json({ error: 'Plan not found' });
    }

    return res.json({ success: true, data: details });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/plans
 * Create a new subscription plan
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const data: CreateSubscriptionPlanDto = req.body;

    if (!data.code || !data.name) {
      return res.status(400).json({ error: 'code and name are required' });
    }

    // Check if code exists
    const existing = await planService.findByCode(data.code);
    if (existing) {
      return res.status(409).json({ error: 'A plan with this code already exists' });
    }

    const plan = await planService.create(data);
    return res.status(201).json({ success: true, data: plan });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/billing/plans/:id
 * Update a subscription plan
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const data: UpdateSubscriptionPlanDto = req.body;
    const plan = await planService.update(req.params.id, data);

    if (!plan) {
      return res.status(404).json({ error: 'Plan not found' });
    }

    return res.json({ success: true, data: plan });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/billing/plans/:id
 * Soft delete a subscription plan
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const deleted = await planService.delete(req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Plan not found' });
    }

    return res.json({ success: true, message: 'Plan deleted' });
  } catch (error) {
    return next(error);
  }
});

// Plan Features

/**
 * GET /api/v1/billing/plans/:id/features
 * Get plan features
 */
router.get('/:id/features', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const features = await planService.getPlanFeatures(req.params.id);

    return res.json({
      success: true,
      data: features,
      count: features.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/plans/:id/features
 * Add a feature to a plan
 */
router.post('/:id/features', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const data: CreatePlanFeatureDto = {
      ...req.body,
      planId: req.params.id,
    };

    if (!data.featureKey || !data.featureName) {
      return res.status(400).json({ error: 'featureKey and featureName are required' });
    }

    const feature = await planService.addPlanFeature(data);
    return res.status(201).json({ success: true, data: feature });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/billing/plans/:planId/features/:featureId
 * Update a plan feature
 */
router.patch('/:planId/features/:featureId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const feature = await planService.updatePlanFeature(req.params.featureId, req.body);

    if (!feature) {
      return res.status(404).json({ error: 'Feature not found' });
    }

    return res.json({ success: true, data: feature });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/billing/plans/:planId/features/:featureId
 * Delete a plan feature
 */
router.delete('/:planId/features/:featureId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const deleted = await planService.deletePlanFeature(req.params.featureId);
    if (!deleted) {
      return res.status(404).json({ error: 'Feature not found' });
    }

    return res.json({ success: true, message: 'Feature deleted' });
  } catch (error) {
    return next(error);
  }
});

// Plan Limits

/**
 * GET /api/v1/billing/plans/:id/limits
 * Get plan limits
 */
router.get('/:id/limits', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const limits = await planService.getPlanLimits(req.params.id);

    return res.json({
      success: true,
      data: limits,
      count: limits.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/plans/:id/limits
 * Add a limit to a plan
 */
router.post('/:id/limits', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const data: CreatePlanLimitDto = {
      ...req.body,
      planId: req.params.id,
    };

    if (!data.limitKey || !data.limitName || data.limitValue === undefined) {
      return res.status(400).json({ error: 'limitKey, limitName, and limitValue are required' });
    }

    const limit = await planService.addPlanLimit(data);
    return res.status(201).json({ success: true, data: limit });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/billing/plans/:planId/limits/:limitId
 * Update a plan limit
 */
router.patch('/:planId/limits/:limitId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const limit = await planService.updatePlanLimit(req.params.limitId, req.body);

    if (!limit) {
      return res.status(404).json({ error: 'Limit not found' });
    }

    return res.json({ success: true, data: limit });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/billing/plans/:planId/limits/:limitId
 * Delete a plan limit
 */
router.delete('/:planId/limits/:limitId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const deleted = await planService.deletePlanLimit(req.params.limitId);
    if (!deleted) {
      return res.status(404).json({ error: 'Limit not found' });
    }

    return res.json({ success: true, message: 'Limit deleted' });
  } catch (error) {
    return next(error);
  }
});

export default router;
