package com.flightticket.controller;

import com.flightticket.dto.error.ErrorResponse;
import com.flightticket.dto.flight.FareRules;
import com.flightticket.dto.flight.FlightOffer;
import com.flightticket.dto.flight.FlightSearchRequest;
import com.flightticket.dto.flight.FlightSearchResponse;
import com.flightticket.security.annotation.RequiresAgent;
import com.flightticket.service.FlightService;
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.ExampleObject;
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.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/api/v1/flights")
@RequiredArgsConstructor
@Tag(name = "Flight Search", description = "Endpoints for searching flights, retrieving offers, and viewing fare rules via Amadeus GDS")
@SecurityRequirement(name = "bearerAuth")
public class FlightController {
    
    private final FlightService flightService;
    
    @Operation(
            summary = "Search for flights",
            description = """
                    Search for available flights using Amadeus GDS.
                    
                    - Queries Amadeus API with origin, destination, dates, and passenger details
                    - Applies agency-specific markup to all prices
                    - Returns available flights with pricing, schedules, and airline information
                    - Results are cached for 30 minutes for performance
                    - Prices include base fare, taxes, and markup separately
                    
                    **Workflow:**
                    1. Submit search criteria
                    2. System queries Amadeus API
                    3. Applies agency markup to prices
                    4. Returns offers with unique offer IDs
                    5. Use offer ID to create booking or view fare rules
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Flight search successful",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = FlightSearchResponse.class),
                            examples = @ExampleObject(value = """
                                    {
                                      "searchId": "search-123e4567-e89b-12d3-a456-426614174000",
                                      "offers": [
                                        {
                                          "offerId": "offer-abc123",
                                          "validatingCarrier": "AA",
                                          "price": {
                                            "baseFare": 500.00,
                                            "taxes": 75.50,
                                            "markup": 28.88,
                                            "total": 604.38,
                                            "currency": "USD"
                                          },
                                          "outboundSegments": [
                                            {
                                              "departureAirport": "JFK",
                                              "arrivalAirport": "LAX",
                                              "departureTime": "2024-02-15T08:00:00",
                                              "arrivalTime": "2024-02-15T11:30:00",
                                              "carrierCode": "AA",
                                              "flightNumber": "100",
                                              "cabinClass": "ECONOMY"
                                            }
                                          ]
                                        }
                                      ],
                                      "expiresAt": "2024-02-14T15:30:00"
                                    }
                                    """)
                    )
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Invalid search parameters",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            ),
            @ApiResponse(
                    responseCode = "403",
                    description = "Agency inactive or insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            ),
            @ApiResponse(
                    responseCode = "503",
                    description = "Amadeus API unavailable",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            )
    })
    @PostMapping("/search")
    @RequiresAgent
    public ResponseEntity<FlightSearchResponse> searchFlights(
            @Valid @RequestBody FlightSearchRequest request,
            @Parameter(description = "Agency UUID") @RequestParam String agencyId) {
        log.info("Flight search request for agency {} from {} to {}", 
                agencyId, request.getOrigin(), request.getDestination());
        FlightSearchResponse response = flightService.searchFlights(request, agencyId);
        
        // Add cache control headers for 30 minutes
        return ResponseEntity.ok()
                .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES))
                .body(response);
    }
    
    @Operation(
            summary = "Get flight offer details",
            description = """
                    Retrieve detailed information about a specific flight offer.
                    
                    - Returns complete offer details including all segments
                    - Includes pricing breakdown with markup
                    - Cached for 30 minutes
                    - Use this before creating a booking
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Offer details retrieved successfully",
                    content = @Content(schema = @Schema(implementation = FlightOffer.class))
            ),
            @ApiResponse(
                    responseCode = "404",
                    description = "Offer not found or expired",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            ),
            @ApiResponse(
                    responseCode = "403",
                    description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            )
    })
    @GetMapping("/offers/{offerId}")
    @RequiresAgent
    public ResponseEntity<FlightOffer> getOfferDetails(
            @Parameter(description = "Unique offer identifier from search results") @PathVariable String offerId) {
        log.info("Get offer details request for offer: {}", offerId);
        FlightOffer offer = flightService.getOfferDetails(offerId);
        
        // Add cache control headers for 30 minutes
        return ResponseEntity.ok()
                .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES))
                .body(offer);
    }
    
    @Operation(
            summary = "Get fare rules for offer",
            description = """
                    Retrieve detailed fare rules and restrictions for a flight offer.
                    
                    - Returns cancellation policies
                    - Shows change fees and penalties
                    - Includes baggage allowances
                    - Lists other restrictions and conditions
                    - Cached for 30 minutes
                    
                    **Important:** Review fare rules before booking to understand ticket conditions.
                    """
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Fare rules retrieved successfully",
                    content = @Content(schema = @Schema(implementation = FareRules.class))
            ),
            @ApiResponse(
                    responseCode = "404",
                    description = "Offer not found or expired",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            ),
            @ApiResponse(
                    responseCode = "403",
                    description = "Insufficient permissions",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            )
    })
    @GetMapping("/offers/{offerId}/fare-rules")
    @RequiresAgent
    public ResponseEntity<FareRules> getFareRules(
            @Parameter(description = "Unique offer identifier from search results") @PathVariable String offerId) {
        log.info("Get fare rules request for offer: {}", offerId);
        FareRules fareRules = flightService.getFareRules(offerId);
        
        // Add cache control headers for 30 minutes
        return ResponseEntity.ok()
                .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES))
                .body(fareRules);
    }
}
