import { Request, Response } from 'express';
import { BaseController } from '../../../shared/controllers/base.controller';
import { LoyaltyService, MembershipQueryOptions } from '../services/loyalty.service';

export class LoyaltyController extends BaseController {
  constructor(private readonly loyaltyService: LoyaltyService) {
    super();
  }

  // ==================== PROGRAM ENDPOINTS ====================

  /**
   * Get active loyalty program
   * GET /loyalty/program
   */
  getActiveProgram = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;

    const program = await this.loyaltyService.getActiveProgram(tenantId);

    if (!program) {
      this.notFound(res, 'Active loyalty program');
      return;
    }

    this.success(res, program);
  };

  // ==================== MEMBERSHIP ENDPOINTS ====================

  /**
   * Enroll customer in loyalty program
   * POST /loyalty/enroll
   */
  enrollCustomer = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const userId = req.userContext!.userId;

    const result = await this.loyaltyService.enrollCustomer(tenantId, req.body, userId);

    if (!result.success) {
      this.error(res, result.error!.message, 400, result.error!.code);
      return;
    }

    this.created(res, result.data);
  };

  /**
   * List memberships
   * GET /loyalty/memberships
   */
  listMemberships = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const options: MembershipQueryOptions = {
      page: Number(req.query.page) || 1,
      limit: Number(req.query.limit) || 20,
      programId: req.query.programId as string,
      levelId: req.query.levelId as string,
      status: req.query.status as any,
      customerId: req.query.customerId as string,
    };

    const result = await this.loyaltyService.findMemberships(tenantId, options);
    this.paginated(res, result.data, result.total, options.page!, options.limit!);
  };

  /**
   * Get membership by customer ID
   * GET /loyalty/memberships/customer/:customerId
   */
  getMembershipByCustomer = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const { customerId } = req.params;
    const programId = req.query.programId as string;

    const membership = await this.loyaltyService.getMembershipByCustomer(
      tenantId,
      customerId,
      programId
    );

    if (!membership) {
      this.notFound(res, 'Membership');
      return;
    }

    this.success(res, membership);
  };

  /**
   * Get membership by card number
   * GET /loyalty/memberships/card/:cardNumber
   */
  getMembershipByCard = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const { cardNumber } = req.params;

    const membership = await this.loyaltyService.getMembershipByCard(tenantId, cardNumber);

    if (!membership) {
      this.notFound(res, 'Membership');
      return;
    }

    this.success(res, membership);
  };

  // ==================== POINTS ENDPOINTS ====================

  /**
   * Calculate points preview
   * POST /loyalty/points/calculate
   */
  calculatePoints = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const { membershipId, purchaseAmount, categoryMultipliers } = req.body;

    const membership = await this.loyaltyService.getMembershipByCustomer(tenantId, membershipId);
    if (!membership) {
      this.error(res, 'Membership not found', 404);
      return;
    }

    const result = await this.loyaltyService.calculatePoints(
      tenantId,
      membership.programId,
      membershipId,
      purchaseAmount,
      categoryMultipliers
    );

    this.success(res, result);
  };

  /**
   * Earn points
   * POST /loyalty/points/earn
   */
  earnPoints = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const userId = req.userContext!.userId;

    const result = await this.loyaltyService.earnPoints(tenantId, req.body, userId);

    if (!result.success) {
      this.error(res, result.error!.message, 400, result.error!.code);
      return;
    }

    this.success(res, result.data, 'Points earned successfully');
  };

  /**
   * Redeem points
   * POST /loyalty/points/redeem
   */
  redeemPoints = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const userId = req.userContext!.userId;

    const result = await this.loyaltyService.redeemPoints(tenantId, req.body, userId);

    if (!result.success) {
      this.error(res, result.error!.message, 400, result.error!.code);
      return;
    }

    this.success(res, result.data, 'Points redeemed successfully');
  };

  /**
   * Adjust points
   * POST /loyalty/points/adjust
   */
  adjustPoints = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const userId = req.userContext!.userId;

    const result = await this.loyaltyService.adjustPoints(tenantId, req.body, userId);

    if (!result.success) {
      this.error(res, result.error!.message, 400, result.error!.code);
      return;
    }

    this.success(res, result.data, 'Points adjusted');
  };

  /**
   * Get expiring points
   * GET /loyalty/memberships/:membershipId/expiring
   */
  getExpiringPoints = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const { membershipId } = req.params;
    const daysAhead = Number(req.query.days) || 30;

    const result = await this.loyaltyService.getExpiringPoints(tenantId, membershipId, daysAhead);
    this.success(res, result);
  };

  // ==================== TRANSACTION ENDPOINTS ====================

  /**
   * Get transaction history
   * GET /loyalty/memberships/:membershipId/transactions
   */
  getTransactionHistory = async (req: Request, res: Response): Promise<void> => {
    const tenantId = req.tenantContext!.tenantId;
    const { membershipId } = req.params;

    const options = {
      page: Number(req.query.page) || 1,
      limit: Number(req.query.limit) || 20,
      type: req.query.type as any,
    };

    const result = await this.loyaltyService.getTransactionHistory(tenantId, membershipId, options);
    this.paginated(res, result.data, result.total, options.page, options.limit);
  };
}
