/**
 * Subscription Plans Controller
 *
 * REST API endpoints for subscription plan management
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { SubscriptionPlansService } from '../services';
import { CreateSubscriptionPlanDto, UpdateSubscriptionPlanDto } from '../dto';

export class SubscriptionPlansController {
  public router: Router;
  private service: SubscriptionPlansService;

  constructor(dataSource: DataSource) {
    this.router = Router();
    this.service = new SubscriptionPlansService(dataSource);
    this.initializeRoutes();
  }

  private initializeRoutes(): void {
    // Public routes
    this.router.get('/public', this.getPublicPlans.bind(this));
    this.router.get('/:id/compare/:otherId', this.comparePlans.bind(this));

    // Protected routes (require admin)
    this.router.get('/', this.getAll.bind(this));
    this.router.get('/:id', this.getById.bind(this));
    this.router.post('/', this.create.bind(this));
    this.router.put('/:id', this.update.bind(this));
    this.router.delete('/:id', this.delete.bind(this));
    this.router.patch('/:id/activate', this.activate.bind(this));
    this.router.patch('/:id/deactivate', this.deactivate.bind(this));
  }

  /**
   * GET /subscription-plans/public
   * Get public plans for pricing page
   */
  private async getPublicPlans(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const plans = await this.service.findPublicPlans();
      res.json({ data: plans });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /subscription-plans
   * Get all plans (admin only)
   */
  private async getAll(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { isActive, isPublic, planType } = req.query;

      const plans = await this.service.findAll({
        isActive: isActive !== undefined ? isActive === 'true' : undefined,
        isPublic: isPublic !== undefined ? isPublic === 'true' : undefined,
        planType: planType as any,
      });

      res.json({ data: plans });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /subscription-plans/:id
   * Get plan by ID
   */
  private async getById(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const plan = await this.service.findById(req.params.id);

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

      res.json({ data: plan });
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /subscription-plans
   * Create new plan
   */
  private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const dto: CreateSubscriptionPlanDto = req.body;
      const plan = await this.service.create(dto);
      res.status(201).json({ data: plan });
    } catch (error) {
      next(error);
    }
  }

  /**
   * PUT /subscription-plans/:id
   * Update plan
   */
  private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const dto: UpdateSubscriptionPlanDto = req.body;
      const plan = await this.service.update(req.params.id, dto);
      res.json({ data: plan });
    } catch (error) {
      next(error);
    }
  }

  /**
   * DELETE /subscription-plans/:id
   * Delete plan (soft delete)
   */
  private async delete(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      await this.service.delete(req.params.id);
      res.status(204).send();
    } catch (error) {
      next(error);
    }
  }

  /**
   * PATCH /subscription-plans/:id/activate
   * Activate plan
   */
  private async activate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const plan = await this.service.setActive(req.params.id, true);
      res.json({ data: plan });
    } catch (error) {
      next(error);
    }
  }

  /**
   * PATCH /subscription-plans/:id/deactivate
   * Deactivate plan
   */
  private async deactivate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const plan = await this.service.setActive(req.params.id, false);
      res.json({ data: plan });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /subscription-plans/:id/compare/:otherId
   * Compare two plans
   */
  private async comparePlans(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const comparison = await this.service.comparePlans(req.params.id, req.params.otherId);
      res.json({ data: comparison });
    } catch (error) {
      next(error);
    }
  }
}
