package com.storycove.controller;

import com.storycove.dto.SeriesDto;
import com.storycove.entity.Collection;
import com.storycove.entity.Series;
import com.storycove.service.CollectionService;
import com.storycove.service.SeriesService;
import jakarta.validation.Valid;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/series")
public class SeriesController {
    
    private final SeriesService seriesService;
    private final CollectionService collectionService;

    public SeriesController(SeriesService seriesService, CollectionService collectionService) {
        this.seriesService = seriesService;
        this.collectionService = collectionService;
    }
    
    @GetMapping
    public ResponseEntity<Page<SeriesDto>> getAllSeries(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(defaultValue = "name") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir) {
        
        Sort sort = sortDir.equalsIgnoreCase("desc") ? 
            Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
        
        Pageable pageable = PageRequest.of(page, size, sort);
        Page<Series> series = seriesService.findAll(pageable);
        Page<SeriesDto> seriesDtos = series.map(this::convertToDto);
        
        return ResponseEntity.ok(seriesDtos);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<SeriesDto> getSeriesById(@PathVariable UUID id) {
        Series series = seriesService.findById(id);
        return ResponseEntity.ok(convertToDto(series));
    }
    
    @PostMapping
    public ResponseEntity<SeriesDto> createSeries(@Valid @RequestBody CreateSeriesRequest request) {
        Series series = new Series();
        updateSeriesFromRequest(series, request);
        
        Series savedSeries = seriesService.create(series);
        return ResponseEntity.status(HttpStatus.CREATED).body(convertToDto(savedSeries));
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<SeriesDto> updateSeries(@PathVariable UUID id, 
                                                 @Valid @RequestBody UpdateSeriesRequest request) {
        Series existingSeries = seriesService.findById(id);
        updateSeriesFromRequest(existingSeries, request);
        
        Series updatedSeries = seriesService.update(id, existingSeries);
        return ResponseEntity.ok(convertToDto(updatedSeries));
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteSeries(@PathVariable UUID id) {
        seriesService.delete(id);
        return ResponseEntity.ok(Map.of("message", "Series deleted successfully"));
    }
    
    @GetMapping("/search")
    public ResponseEntity<Page<SeriesDto>> searchSeries(
            @RequestParam String query,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size);
        Page<Series> series = seriesService.searchByName(query, pageable);
        Page<SeriesDto> seriesDtos = series.map(this::convertToDto);
        
        return ResponseEntity.ok(seriesDtos);
    }
    
    @GetMapping("/with-stories")
    public ResponseEntity<List<SeriesDto>> getSeriesWithStories(@RequestParam(defaultValue = "20") int limit) {
        Pageable pageable = PageRequest.of(0, limit);
        List<Series> series = seriesService.findSeriesWithStoriesLimited(pageable);
        List<SeriesDto> seriesDtos = series.stream().map(this::convertToDto).collect(Collectors.toList());
        
        return ResponseEntity.ok(seriesDtos);
    }
    
    @GetMapping("/popular")
    public ResponseEntity<List<SeriesDto>> getPopularSeries(@RequestParam(defaultValue = "10") int limit) {
        List<Series> series = seriesService.findMostPopular(limit);
        List<SeriesDto> seriesDtos = series.stream().map(this::convertToDto).collect(Collectors.toList());
        
        return ResponseEntity.ok(seriesDtos);
    }
    
    @GetMapping("/empty")
    public ResponseEntity<List<SeriesDto>> getEmptySeries() {
        List<Series> series = seriesService.findEmptySeries();
        List<SeriesDto> seriesDtos = series.stream().map(this::convertToDto).collect(Collectors.toList());
        
        return ResponseEntity.ok(seriesDtos);
    }
    
    @GetMapping("/stats")
    public ResponseEntity<Map<String, Object>> getSeriesStats() {
        long totalSeries = seriesService.countAll();
        long seriesWithStories = seriesService.countSeriesWithStories();
        long emptySeries = totalSeries - seriesWithStories;
        
        Map<String, Object> stats = Map.of(
            "totalSeries", totalSeries,
            "seriesWithStories", seriesWithStories,
            "emptySeries", emptySeries
        );
        
        return ResponseEntity.ok(stats);
    }
    
    @PostMapping("/{id}/create-collection")
    public ResponseEntity<Map<String, String>> createCollectionFromSeries(@PathVariable UUID id) {
        Collection collection = collectionService.createCollectionFromSeries(id);
        return ResponseEntity.status(HttpStatus.CREATED).body(Map.of(
            "collectionId", collection.getId().toString(),
            "name", collection.getName()
        ));
    }

    private void updateSeriesFromRequest(Series series, Object request) {
        if (request instanceof CreateSeriesRequest createReq) {
            series.setName(createReq.getName());
            series.setDescription(createReq.getDescription());
        } else if (request instanceof UpdateSeriesRequest updateReq) {
            if (updateReq.getName() != null) {
                series.setName(updateReq.getName());
            }
            if (updateReq.getDescription() != null) {
                series.setDescription(updateReq.getDescription());
            }
        }
    }
    
    private SeriesDto convertToDto(Series series) {
        SeriesDto dto = new SeriesDto();
        dto.setId(series.getId());
        dto.setName(series.getName());
        dto.setDescription(series.getDescription());
        dto.setStoryCount(series.getStories() != null ? series.getStories().size() : 0);
        dto.setCreatedAt(series.getCreatedAt());
        
        return dto;
    }
    
    // Request DTOs
    public static class CreateSeriesRequest {
        private String name;
        private String description;
        
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }
    
    public static class UpdateSeriesRequest {
        private String name;
        private String description;
        
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }
}