import {
  Controller,
  Get,
  Post,
  Param,
  Query,
  Body,
  Request,
  ParseIntPipe,
  BadRequestException,
  UsePipes,
  Header,
} from "@nestjs/common";
import { SubscriptionsService } from "./subscriptions.service";
import { SimManagementService } from "./sim-management.service";
import { SimTopUpPricingService } from "./sim-management/services/sim-topup-pricing.service";

import {
  Subscription,
  SubscriptionList,
  SubscriptionStats,
  SimActionResponse,
  SimPlanChangeResult,
  subscriptionQuerySchema,
  type SubscriptionQuery,
} from "@customer-portal/domain/subscriptions";
import { InvoiceList } from "@customer-portal/domain/billing";
import { createPaginationSchema } from "@customer-portal/domain/toolkit/validation/helpers";
import type { z } from "zod";
import {
  simTopupRequestSchema,
  simChangePlanRequestSchema,
  simCancelRequestSchema,
  simFeaturesRequestSchema,
  simCancelFullRequestSchema,
  simChangePlanFullRequestSchema,
  type SimTopupRequest,
  type SimChangePlanRequest,
  type SimCancelRequest,
  type SimFeaturesRequest,
  type SimCancelFullRequest,
  type SimChangePlanFullRequest,
} from "@customer-portal/domain/sim";
import { ZodValidationPipe } from "@customer-portal/validation/nestjs";
import type { RequestWithUser } from "@bff/modules/auth/auth.types";
import { SimPlanService } from "./sim-management/services/sim-plan.service";
import { SimCancellationService } from "./sim-management/services/sim-cancellation.service";
import { EsimManagementService, type ReissueSimRequest } from "./sim-management/services/esim-management.service";

const subscriptionInvoiceQuerySchema = createPaginationSchema({
  defaultLimit: 10,
  maxLimit: 100,
  minLimit: 1,
});
type SubscriptionInvoiceQuery = z.infer<typeof subscriptionInvoiceQuerySchema>;

@Controller("subscriptions")
export class SubscriptionsController {
  constructor(
    private readonly subscriptionsService: SubscriptionsService,
    private readonly simManagementService: SimManagementService,
    private readonly simTopUpPricingService: SimTopUpPricingService,
    private readonly simPlanService: SimPlanService,
    private readonly simCancellationService: SimCancellationService,
    private readonly esimManagementService: EsimManagementService
  ) {}

  @Get()
  @Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
  @UsePipes(new ZodValidationPipe(subscriptionQuerySchema))
  async getSubscriptions(
    @Request() req: RequestWithUser,
    @Query() query: SubscriptionQuery
  ): Promise<SubscriptionList> {
    const { status } = query;
    return this.subscriptionsService.getSubscriptions(req.user.id, { status });
  }

  @Get("active")
  @Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
  async getActiveSubscriptions(@Request() req: RequestWithUser): Promise<Subscription[]> {
    return this.subscriptionsService.getActiveSubscriptions(req.user.id);
  }

  @Get("stats")
  @Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
  async getSubscriptionStats(@Request() req: RequestWithUser): Promise<SubscriptionStats> {
    return this.subscriptionsService.getSubscriptionStats(req.user.id);
  }

  @Get(":id")
  @Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
  async getSubscriptionById(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ): Promise<Subscription> {
    return this.subscriptionsService.getSubscriptionById(req.user.id, subscriptionId);
  }
  @Get(":id/invoices")
  @Header("Cache-Control", "private, max-age=60") // 1 minute, may update with payments
  async getSubscriptionInvoices(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Query(new ZodValidationPipe(subscriptionInvoiceQuerySchema)) query: SubscriptionInvoiceQuery
  ): Promise<InvoiceList> {
    return this.subscriptionsService.getSubscriptionInvoices(req.user.id, subscriptionId, query);
  }

  // ==================== SIM Management Endpoints ====================

  @Get("sim/top-up/pricing")
  @Header("Cache-Control", "public, max-age=3600") // 1 hour, pricing is relatively static
  async getSimTopUpPricing() {
    const pricing = await this.simTopUpPricingService.getTopUpPricing();
    return { success: true, data: pricing };
  }

  @Get("sim/top-up/pricing/preview")
  @Header("Cache-Control", "public, max-age=3600") // 1 hour, pricing calculation is deterministic
  async previewSimTopUpPricing(@Query("quotaMb") quotaMb: string) {
    const quotaMbNum = parseInt(quotaMb, 10);
    if (isNaN(quotaMbNum) || quotaMbNum <= 0) {
      throw new BadRequestException("Invalid quotaMb parameter");
    }

    const preview = await this.simTopUpPricingService.calculatePricingPreview(quotaMbNum);
    return { success: true, data: preview };
  }

  @Get("debug/sim-details/:account")
  async debugSimDetails(@Param("account") account: string) {
    return await this.simManagementService.getSimDetailsDebug(account);
  }

  @Get(":id/sim/debug")
  async debugSimSubscription(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ): Promise<Record<string, unknown>> {
    return this.simManagementService.debugSimSubscription(req.user.id, subscriptionId);
  }

  @Get(":id/sim")
  async getSimInfo(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ) {
    return this.simManagementService.getSimInfo(req.user.id, subscriptionId);
  }

  @Get(":id/sim/details")
  async getSimDetails(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ) {
    return this.simManagementService.getSimDetails(req.user.id, subscriptionId);
  }

  @Get(":id/sim/usage")
  async getSimUsage(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ) {
    return this.simManagementService.getSimUsage(req.user.id, subscriptionId);
  }

  @Get(":id/sim/top-up-history")
  async getSimTopUpHistory(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Query("fromDate") fromDate: string,
    @Query("toDate") toDate: string
  ) {
    if (!fromDate || !toDate) {
      throw new BadRequestException("fromDate and toDate are required");
    }

    return this.simManagementService.getSimTopUpHistory(req.user.id, subscriptionId, {
      fromDate,
      toDate,
    });
  }

  @Post(":id/sim/top-up")
  @UsePipes(new ZodValidationPipe(simTopupRequestSchema))
  async topUpSim(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimTopupRequest
  ): Promise<SimActionResponse> {
    await this.simManagementService.topUpSim(req.user.id, subscriptionId, body);
    return { success: true, message: "SIM top-up completed successfully" };
  }

  @Post(":id/sim/change-plan")
  @UsePipes(new ZodValidationPipe(simChangePlanRequestSchema))
  async changeSimPlan(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimChangePlanRequest
  ): Promise<SimPlanChangeResult> {
    const result = await this.simManagementService.changeSimPlan(req.user.id, subscriptionId, body);
    return {
      success: true,
      message: "SIM plan change completed successfully",
      ...result,
    };
  }

  @Post(":id/sim/cancel")
  @UsePipes(new ZodValidationPipe(simCancelRequestSchema))
  async cancelSim(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimCancelRequest
  ): Promise<SimActionResponse> {
    await this.simManagementService.cancelSim(req.user.id, subscriptionId, body);
    return { success: true, message: "SIM cancellation completed successfully" };
  }

  @Post(":id/sim/reissue-esim")
  async reissueEsimProfile(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: { newEid?: string } = {}
  ): Promise<SimActionResponse> {
    await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId, body.newEid);
    return { success: true, message: "eSIM profile reissue completed successfully" };
  }

  @Post(":id/sim/features")
  @UsePipes(new ZodValidationPipe(simFeaturesRequestSchema))
  async updateSimFeatures(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimFeaturesRequest
  ): Promise<SimActionResponse> {
    await this.simManagementService.updateSimFeatures(req.user.id, subscriptionId, body);
    return { success: true, message: "SIM features updated successfully" };
  }

  // ==================== Enhanced SIM Management Endpoints ====================

  /**
   * Get available plans for plan change (filtered by current plan type)
   */
  @Get(":id/sim/available-plans")
  @Header("Cache-Control", "private, max-age=300")
  async getAvailablePlans(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ) {
    const plans = await this.simPlanService.getAvailablePlans(req.user.id, subscriptionId);
    return { success: true, data: plans };
  }

  /**
   * Change SIM plan with enhanced flow (Salesforce SKU mapping + email notifications)
   */
  @Post(":id/sim/change-plan-full")
  @UsePipes(new ZodValidationPipe(simChangePlanFullRequestSchema))
  async changeSimPlanFull(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimChangePlanFullRequest
  ): Promise<SimPlanChangeResult> {
    const result = await this.simPlanService.changeSimPlanFull(req.user.id, subscriptionId, body);
    return {
      success: true,
      message: `SIM plan change scheduled for ${result.scheduledAt}`,
      ...result,
    };
  }

  /**
   * Get cancellation preview (available months, customer info, minimum contract term)
   */
  @Get(":id/sim/cancellation-preview")
  @Header("Cache-Control", "private, max-age=60")
  async getCancellationPreview(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number
  ) {
    const preview = await this.simCancellationService.getCancellationPreview(
      req.user.id,
      subscriptionId
    );
    return { success: true, data: preview };
  }

  /**
   * Cancel SIM with full flow (PA02-04 + email notifications)
   */
  @Post(":id/sim/cancel-full")
  @UsePipes(new ZodValidationPipe(simCancelFullRequestSchema))
  async cancelSimFull(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: SimCancelFullRequest
  ): Promise<SimActionResponse> {
    await this.simCancellationService.cancelSimFull(req.user.id, subscriptionId, body);
    return {
      success: true,
      message: `SIM cancellation scheduled for end of ${body.cancellationMonth}`,
    };
  }

  /**
   * Reissue SIM (both eSIM and physical SIM)
   */
  @Post(":id/sim/reissue")
  async reissueSim(
    @Request() req: RequestWithUser,
    @Param("id", ParseIntPipe) subscriptionId: number,
    @Body() body: ReissueSimRequest
  ): Promise<SimActionResponse> {
    await this.esimManagementService.reissueSim(req.user.id, subscriptionId, body);
    
    if (body.simType === "esim") {
      return { success: true, message: "eSIM profile reissue request submitted" };
    } else {
      return { success: true, message: "Physical SIM reissue request submitted. You will be contacted shortly." };
    }
  }
}
