package com.social.media.interfaces.web.controller;

import com.social.media.application.campaign.dto.*;
import com.social.media.application.campaign.service.CampaignApplicationService;
import com.social.media.domain.campaign.service.CampaignDomainService;
import com.social.media.domain.campaign.valueobject.CampaignInteractionStatus;
import com.social.media.domain.campaign.valueobject.CampaignInteractionType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import com.social.media.domain.user.valueobject.UserId;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

/**
 * REST Controller for Campaign operations
 */
@RestController
@RequestMapping("/api/v1/campaigns")
@Tag(name = "Campaigns", description = "API for managing social media campaigns")
@CrossOrigin(origins = "*", maxAge = 3600)
public class CampaignController {
    
    private final CampaignApplicationService applicationService;
    
    public CampaignController(CampaignApplicationService applicationService) {
        this.applicationService = applicationService;
    }
    
    @PostMapping
    @Operation(summary = "Create a new campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> createCampaign(
            @Valid @RequestBody CreateCampaignDTO dto) {
        
        var authInfo = getAuthenticatedUserInfo();
        // Authentication context handled by the service layer
        
        CampaignDTO created = applicationService.createCampaign(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
    
    @GetMapping("/{id}")
    @Operation(summary = "Get campaign by ID")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> getCampaignById(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        var authInfo = getAuthenticatedUserInfo();
        Optional<CampaignDTO> campaign = applicationService.getCampaignById(id);
        return campaign.map(ResponseEntity::ok)
                      .orElse(ResponseEntity.notFound().build());
    }
    
    @PutMapping("/{id}")
    @Operation(summary = "Update campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> updateCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id,
            @Valid @RequestBody UpdateCampaignDTO dto) {
        
        var authInfo = getAuthenticatedUserInfo();
        CampaignDTO updated = applicationService.updateCampaign(id, dto);
        return ResponseEntity.ok(updated);
    }
    
    @DeleteMapping("/{id}")
    @Operation(summary = "Delete campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<Void> deleteCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        var authInfo = getAuthenticatedUserInfo();
        applicationService.deleteCampaign(id);
        return ResponseEntity.noContent().build();
    }
    
    @GetMapping("/user/{userId}")
    @Operation(summary = "Get all campaigns for a user")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByUserId(
            @Parameter(description = "User ID") @PathVariable Long userId) {
        
        var authInfo = getAuthenticatedUserInfo();
        // Verify access: user can only see their own campaigns unless admin
        if (!authInfo.userId().value().equals(userId) && !hasAdminRole()) {
            return ResponseEntity.status(403).build();
        }
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByUserId(userId);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/user/{userId}/status/{status}")
    @Operation(summary = "Get campaigns by user and status")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByUserIdAndStatus(
            @Parameter(description = "User ID") @PathVariable Long userId,
            @Parameter(description = "Campaign status") @PathVariable CampaignInteractionStatus status) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByUserIdAndStatus(userId, status);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/user/{userId}/type/{interactionType}")
    @Operation(summary = "Get campaigns by user and interaction type")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByUserIdAndInteractionType(
            @Parameter(description = "User ID") @PathVariable Long userId,
            @Parameter(description = "Interaction type") @PathVariable CampaignInteractionType interactionType) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByUserIdAndInteractionType(userId, interactionType);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/bot/{botId}")
    @Operation(summary = "Get campaigns by bot")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByBotId(
            @Parameter(description = "Bot ID") @PathVariable Long botId) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByBotId(botId);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/account/{accountNetworkId}")
    @Operation(summary = "Get campaigns by social account")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByAccountNetworkId(
            @Parameter(description = "Account Network ID") @PathVariable Long accountNetworkId) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByAccountNetworkId(accountNetworkId);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/active")
    @Operation(summary = "Get all active campaigns")
    @PreAuthorize("hasRole('ADMIN') or hasRole('MANAGER')")
    public ResponseEntity<List<CampaignDTO>> getActiveCampaigns() {
        
        var authInfo = getAuthenticatedUserInfo();
        List<CampaignDTO> campaigns = applicationService.getActiveCampaigns();
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/scheduled/{date}")
    @Operation(summary = "Get campaigns scheduled for a specific date")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsScheduledForDate(
            @Parameter(description = "Date") 
            @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsScheduledForDate(date);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/user/{userId}/date-range")
    @Operation(summary = "Get campaigns by user and date range")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> getCampaignsByDateRange(
            @Parameter(description = "User ID") @PathVariable Long userId,
            @Parameter(description = "Start date") 
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @Parameter(description = "End date") 
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
        
        List<CampaignDTO> campaigns = applicationService.getCampaignsByDateRange(userId, startDate, endDate);
        return ResponseEntity.ok(campaigns);
    }
    
    @PostMapping("/{id}/start")
    @Operation(summary = "Start a campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> startCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        CampaignDTO campaign = applicationService.startCampaign(id);
        return ResponseEntity.ok(campaign);
    }
    
    @PostMapping("/{id}/pause")
    @Operation(summary = "Pause a campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> pauseCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        CampaignDTO campaign = applicationService.pauseCampaign(id);
        return ResponseEntity.ok(campaign);
    }
    
    @PostMapping("/{id}/resume")
    @Operation(summary = "Resume a paused campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> resumeCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        CampaignDTO campaign = applicationService.resumeCampaign(id);
        return ResponseEntity.ok(campaign);
    }
    
    @PostMapping("/{id}/complete")
    @Operation(summary = "Complete a campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> completeCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        CampaignDTO campaign = applicationService.completeCampaign(id);
        return ResponseEntity.ok(campaign);
    }
    
    @PostMapping("/{id}/cancel")
    @Operation(summary = "Cancel a campaign")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDTO> cancelCampaign(
            @Parameter(description = "Campaign ID") @PathVariable Long id) {
        
        CampaignDTO campaign = applicationService.cancelCampaign(id);
        return ResponseEntity.ok(campaign);
    }
    
    @PostMapping("/bulk-status-change")
    @Operation(summary = "Bulk status change for multiple campaigns")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<List<CampaignDTO>> bulkStatusChange(
            @Valid @RequestBody BulkStatusChangeDTO dto,
            @Parameter(description = "User ID") @RequestParam Long userId) {
        
        List<CampaignDTO> campaigns = applicationService.bulkStatusChange(dto, userId);
        return ResponseEntity.ok(campaigns);
    }
    
    @GetMapping("/user/{userId}/statistics")
    @Operation(summary = "Get campaign statistics for a user")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<CampaignDomainService.CampaignStatistics> getCampaignStatistics(
            @Parameter(description = "User ID") @PathVariable Long userId) {
        
        var authInfo = getAuthenticatedUserInfo();
        // Verify access: user can only see their own statistics unless admin
        if (!authInfo.userId().value().equals(userId) && !hasAdminRole()) {
            return ResponseEntity.status(403).build();
        }
        
        CampaignDomainService.CampaignStatistics stats = applicationService.getCampaignStatistics(userId);
        return ResponseEntity.ok(stats);
    }
    
    @GetMapping("/interaction-types")
    @Operation(summary = "Get all available interaction types")
    public ResponseEntity<CampaignInteractionType[]> getInteractionTypes() {
        return ResponseEntity.ok(applicationService.getInteractionTypes());
    }
    
    @GetMapping("/interaction-statuses")
    @Operation(summary = "Get all available interaction statuses")
    public ResponseEntity<CampaignInteractionStatus[]> getInteractionStatuses() {
        return ResponseEntity.ok(applicationService.getInteractionStatuses());
    }
    
    /**
     * Helper method to get authenticated user information
     */
    private AuthenticatedUserInfo getAuthenticatedUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("User not authenticated");
        }
        
        // Extract user ID and company ID from authentication
        Long userId = extractUserIdFromAuthentication(authentication);
        Long companyId = extractCompanyIdFromAuthentication(authentication);
        
        return new AuthenticatedUserInfo(UserId.of(userId), companyId);
    }
    
    private Long extractUserIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        return 1L; // Temporary
    }
    
    private Long extractCompanyIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        return 1L; // Temporary
    }
    
    private boolean hasAdminRole() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication.getAuthorities().stream()
                .anyMatch(authority -> authority.getAuthority().equals("ROLE_ADMIN"));
    }
    
    /**
     * Record to hold authenticated user information
     */
    private record AuthenticatedUserInfo(UserId userId, Long companyId) {}
}
