package de.oaa.xxx.games.chastity.cardlock;

import de.oaa.xxx.games.chastity.tasks.Task;
import de.oaa.xxx.games.chastity.tasks.TaskMode;
import de.oaa.xxx.subscription.SubscriptionLimitService;
import de.oaa.xxx.user.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import de.oaa.xxx.games.chastity.timelock.TimeLockTemplateRepository;

import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/cardlock/templates")
public class CardlockTemplateController {

    private final CardlockTemplateRepository templateRepository;
    private final UserService userService;
    private final TimeLockTemplateRepository timeLockTemplateRepository;
    private final SubscriptionLimitService limitService;

    public CardlockTemplateController(CardlockTemplateRepository templateRepository,
                                      UserService userService,
                                      TimeLockTemplateRepository timeLockTemplateRepository,
                                      SubscriptionLimitService limitService) {
        this.templateRepository = templateRepository;
        this.userService = userService;
        this.timeLockTemplateRepository = timeLockTemplateRepository;
        this.limitService = limitService;
    }

    record TemplateRequest(
            String name,
            Map<String, Integer> cardCountsMin,
            Map<String, Integer> cardCountsMax,
            Integer pickEveryMinute,
            boolean accumulatePicks,
            boolean showRemainingCards,
            Integer hygineOpeningDurationMinutes,
            Integer hygineOpeningEveryMinites,
            List<Task> tasks,
            boolean requiresVerification,
            TaskMode taskMode
    ) {}

    private Map<String, Object> toDto(CardlockTemplateEntity t) {
        Map<String, Object> dto = new LinkedHashMap<>();
        dto.put("templateId",                    t.getTemplateId());
        dto.put("name",                          t.getName());
        dto.put("cardCountsMin",                 t.getCardCountsMin() != null ? t.getCardCountsMin() : Map.of());
        dto.put("cardCountsMax",                 t.getCardCountsMax() != null ? t.getCardCountsMax() : Map.of());
        dto.put("pickEveryMinute",               t.getPickEveryMinute());
        dto.put("accumulatePicks",               t.isAccumulatePicks());
        dto.put("showRemainingCards",            t.isShowRemainingCards());
        dto.put("hygineOpeningEveryMinites",     t.getHygineOpeningEveryMinites());
        dto.put("hygineOpeningDurationMinutes",  t.getHygineOpeningDurationMinutes());
        dto.put("tasks",                         t.getTasks() != null ? t.getTasks() : List.of());
        dto.put("requiresVerification",          t.isRequiresVerification());
        dto.put("taskCardMode",                  t.getTaskCardMode());
        return dto;
    }

    @GetMapping
    public ResponseEntity<List<Map<String, Object>>> list(Principal principal) {
        UUID myId = userService.requireUser(principal).getUserId();
        List<Map<String, Object>> result = templateRepository.findByOwner(myId)
                .stream().map(this::toDto).collect(Collectors.toList());
        return ResponseEntity.ok(result);
    }

    @PostMapping
    public ResponseEntity<Map<String, Object>> create(@RequestBody TemplateRequest req, Principal principal) {
        UUID myId = userService.requireUser(principal).getUserId();

        if (req.pickEveryMinute() == null || req.pickEveryMinute() < 1)
            return ResponseEntity.badRequest().build();
        if (req.cardCountsMin() == null || req.cardCountsMin().isEmpty())
            return ResponseEntity.badRequest().build();

        long totalTemplates = templateRepository.countByOwner(myId)
                + timeLockTemplateRepository.countByOwner(myId);
        if (totalTemplates >= limitService.maxLockTemplates(myId))
            return ResponseEntity.status(409).header("X-Error", "limit-reached").build();

        CardlockTemplateEntity t = new CardlockTemplateEntity();
        t.setOwner(myId);
        applyRequest(t, req);
        templateRepository.save(t);
        return ResponseEntity.ok(toDto(t));
    }

    @PutMapping("/{id}")
    public ResponseEntity<Map<String, Object>> update(@PathVariable UUID id,
                                                      @RequestBody TemplateRequest req,
                                                      Principal principal) {
        UUID myId = userService.requireUser(principal).getUserId();

        var opt = templateRepository.findById(id);
        if (opt.isEmpty()) return ResponseEntity.notFound().build();
        CardlockTemplateEntity t = opt.get();
        if (!t.getOwner().equals(myId)) return ResponseEntity.status(403).build();

        if (req.pickEveryMinute() == null || req.pickEveryMinute() < 1)
            return ResponseEntity.badRequest().build();
        if (req.cardCountsMin() == null || req.cardCountsMin().isEmpty())
            return ResponseEntity.badRequest().build();

        applyRequest(t, req);
        templateRepository.save(t);
        return ResponseEntity.ok(toDto(t));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable UUID id, Principal principal) {
        UUID myId = userService.requireUser(principal).getUserId();

        var opt = templateRepository.findById(id);
        if (opt.isEmpty()) return ResponseEntity.notFound().build();
        if (!opt.get().getOwner().equals(myId)) return ResponseEntity.status(403).build();

        templateRepository.deleteById(id);
        return ResponseEntity.noContent().build();
    }

    private void applyRequest(CardlockTemplateEntity t, TemplateRequest req) {
        t.setName(req.name());
        t.setCardCountsMin(req.cardCountsMin());
        t.setCardCountsMax(req.cardCountsMax() != null ? req.cardCountsMax() : req.cardCountsMin());
        t.setPickEveryMinute(req.pickEveryMinute());
        t.setAccumulatePicks(req.accumulatePicks());
        t.setShowRemainingCards(req.showRemainingCards());
        t.setHygineOpeningEveryMinites(req.hygineOpeningEveryMinites());
        t.setHygineOpeningDurationMinutes(req.hygineOpeningDurationMinutes());
        t.setTasks(req.tasks() != null ? req.tasks() : List.of());
        t.setRequiresVerification(req.requiresVerification());
        t.setTaskMode(req.taskMode() != null ? req.taskMode() : TaskMode.RANDOM);
    }
}
