package com.flightticket.controller;

import com.flightticket.dto.agency.AgencyResponse;
import com.flightticket.dto.agency.CreateAgencyRequest;
import com.flightticket.dto.agency.UpdateAgencyRequest;
import com.flightticket.dto.error.ErrorResponse;
import com.flightticket.model.enums.SubscriptionType;
import com.flightticket.security.annotation.RequiresSuperAdmin;
import com.flightticket.service.AgencyManagementService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/api/v1/agencies")
@RequiredArgsConstructor
@Tag(name = "Agency Management", description = "Endpoints for managing sub-agencies including creation, verification, subscription management, and markup configuration")
@SecurityRequirement(name = "bearerAuth")
public class AgencyManagementController {
    
    private final AgencyManagementService agencyManagementService;
    
    @Operation(
            summary = "Create new agency",
            description = """
                    Create a new sub-agency with KYC documentation and subscription plan.
                    
                    - Only SUPER_ADMIN can create agencies
                    - Requires unique matricule number
                    - Initializes wallet with zero balance
                    - Agency starts in PENDING_VERIFICATION status
                    - Must be verified before users can perform transactions
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "Agency created successfully"),
            @ApiResponse(responseCode = "400", description = "Invalid request or duplicate matricule number",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> createAgency(
            @Valid @RequestBody CreateAgencyRequest request,
            Authentication authentication) {
        log.info("Create agency request received: {}", request.getName());
        UUID createdBy = UUID.fromString(authentication.getName());
        AgencyResponse response = agencyManagementService.createAgency(request, createdBy);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
    
    @Operation(
            summary = "Get agency by ID",
            description = "Retrieve detailed information about a specific agency"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agency found"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping("/{agencyId}")
    public ResponseEntity<AgencyResponse> getAgencyById(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId) {
        log.info("Get agency request for ID: {}", agencyId);
        AgencyResponse response = agencyManagementService.getAgencyById(agencyId);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Get all agencies",
            description = "Retrieve list of all agencies (SUPER_ADMIN only)"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agencies retrieved successfully"),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping
    @RequiresSuperAdmin
    public ResponseEntity<List<AgencyResponse>> getAllAgencies() {
        log.info("Get all agencies request");
        List<AgencyResponse> responses = agencyManagementService.getAllAgencies();
        return ResponseEntity.ok(responses);
    }
    
    @Operation(
            summary = "Get pending verification agencies",
            description = "Retrieve agencies awaiting verification (SUPER_ADMIN only)"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Pending agencies retrieved"),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping("/pending-verification")
    @RequiresSuperAdmin
    public ResponseEntity<List<AgencyResponse>> getPendingVerificationAgencies() {
        log.info("Get pending verification agencies request");
        List<AgencyResponse> responses = agencyManagementService.getPendingVerificationAgencies();
        return ResponseEntity.ok(responses);
    }
    
    @Operation(
            summary = "Get agencies nearing expiration",
            description = "Retrieve agencies whose subscriptions are expiring soon (SUPER_ADMIN only)"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Expiring agencies retrieved"),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping("/expiring")
    @RequiresSuperAdmin
    public ResponseEntity<List<AgencyResponse>> getAgenciesNearingExpiration(
            @Parameter(description = "Number of days threshold") @RequestParam(defaultValue = "7") int daysThreshold) {
        log.info("Get agencies nearing expiration within {} days", daysThreshold);
        List<AgencyResponse> responses = agencyManagementService.getAgenciesNearingExpiration(daysThreshold);
        return ResponseEntity.ok(responses);
    }
    
    @Operation(
            summary = "Update agency",
            description = "Update agency information (SUPER_ADMIN only)"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agency updated successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PutMapping("/{agencyId}")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> updateAgency(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            @Valid @RequestBody UpdateAgencyRequest request) {
        log.info("Update agency request for ID: {}", agencyId);
        AgencyResponse response = agencyManagementService.updateAgency(agencyId, request);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Verify agency",
            description = """
                    Verify agency KYC and activate for transactions (SUPER_ADMIN only).
                    
                    - Sets is_verified to TRUE
                    - Changes status to ACTIVE
                    - Records verification timestamp and verifier
                    - Enables users to perform transactions
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agency verified successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "403", description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping("/{agencyId}/verify")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> verifyAgency(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            Authentication authentication) {
        log.info("Verify agency request for ID: {}", agencyId);
        UUID verifiedBy = UUID.fromString(authentication.getName());
        AgencyResponse response = agencyManagementService.verifyAgency(agencyId, verifiedBy);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Activate agency",
            description = "Manually activate an agency (SUPER_ADMIN only)"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agency activated successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping("/{agencyId}/activate")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> activateAgency(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            Authentication authentication) {
        log.info("Activate agency request for ID: {}", agencyId);
        UUID activatedBy = UUID.fromString(authentication.getName());
        AgencyResponse response = agencyManagementService.activateAgency(agencyId, activatedBy);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Deactivate agency",
            description = """
                    Manually deactivate an agency with reason (SUPER_ADMIN only).
                    
                    - Prevents all users from performing transactions
                    - Records deactivation timestamp, user, and reason
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Agency deactivated successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping("/{agencyId}/deactivate")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> deactivateAgency(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            @Parameter(description = "Reason for deactivation") @RequestParam String reason,
            Authentication authentication) {
        log.info("Deactivate agency request for ID: {} with reason: {}", agencyId, reason);
        UUID deactivatedBy = UUID.fromString(authentication.getName());
        AgencyResponse response = agencyManagementService.deactivateAgency(agencyId, deactivatedBy, reason);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Update agency markup",
            description = """
                    Update commission percentage for an agency (SUPER_ADMIN only).
                    
                    - Applied to all subsequent flight searches
                    - Markup history is maintained for audit
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Markup updated successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PutMapping("/{agencyId}/markup")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> updateMarkup(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            @Parameter(description = "Markup percentage (e.g., 5.5 for 5.5%)") @RequestParam BigDecimal markupPercentage,
            Authentication authentication) {
        log.info("Update markup for agency {} to {}%", agencyId, markupPercentage);
        UUID updatedBy = UUID.fromString(authentication.getName());
        AgencyResponse response = agencyManagementService.updateMarkup(agencyId, markupPercentage, updatedBy);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Record subscription payment",
            description = """
                    Record a subscription payment for an agency (SUPER_ADMIN only).
                    
                    - Updates last payment date
                    - Calculates next payment due date based on subscription type
                    - Prevents automatic deactivation
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Payment recorded successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping("/{agencyId}/payment")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> recordPayment(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            @Parameter(description = "Payment date") @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate paymentDate) {
        log.info("Record payment for agency {} on date {}", agencyId, paymentDate);
        AgencyResponse response = agencyManagementService.recordPayment(agencyId, paymentDate);
        return ResponseEntity.ok(response);
    }
    
    @Operation(
            summary = "Renew agency subscription",
            description = """
                    Renew or change subscription type for an agency (SUPER_ADMIN only).
                    
                    - Can change between MONTHLY and ANNUAL
                    - Resets subscription start date
                    - Calculates new payment due date
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Subscription renewed successfully"),
            @ApiResponse(responseCode = "404", description = "Agency not found",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @PostMapping("/{agencyId}/renew")
    @RequiresSuperAdmin
    public ResponseEntity<AgencyResponse> renewSubscription(
            @Parameter(description = "Agency UUID") @PathVariable UUID agencyId,
            @Parameter(description = "New subscription type") @RequestParam SubscriptionType subscriptionType) {
        log.info("Renew subscription for agency {} with type {}", agencyId, subscriptionType);
        AgencyResponse response = agencyManagementService.renewSubscription(agencyId, subscriptionType);
        return ResponseEntity.ok(response);
    }
}
