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

import de.oaa.xxx.games.chastity.cardlock.CardlockTemplateRepository;
import de.oaa.xxx.games.chastity.common.PenaltyType;
import de.oaa.xxx.games.chastity.spinningwheel.SpinningWheelEntry;
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 java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/timelock/templates")
public class TimeLockTemplateController {

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

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

    record TemplateRequest(
            String name,
            Integer minTimeInMinutes,
            Integer maxTimeInMinutes,
            boolean endTimeVisible,
            Integer hygineOpeningDurationMinutes,
            Integer hygineOpeningEveryMinites,
            List<Task> tasks,
            Integer taskEveryMinutes,
            Integer minTasksPerDay,
            List<SpinningWheelEntry> spinningWheelEntries,
            Integer spinsEveryMinutes,
            Integer minSpinsPerDay,
            boolean requiresVerification,
            TaskMode taskMode,
            PenaltyType penaltyType,
            Integer penaltyValue
    ) {}

    private Map<String, Object> toDto(TimeLockTemplateEntity t) {
        Map<String, Object> dto = new LinkedHashMap<>();
        dto.put("templateId",                    t.getTemplateId());
        dto.put("name",                          t.getName());
        dto.put("minTimeInMinutes",              t.getMinTimeInMinutes());
        dto.put("maxTimeInMinutes",              t.getMaxTimeInMinutes());
        dto.put("endTimeVisible",                t.isEndTimeVisible());
        dto.put("hygineOpeningEveryMinites",     t.getHygineOpeningEveryMinites());
        dto.put("hygineOpeningDurationMinutes",  t.getHygineOpeningDurationMinutes());
        dto.put("tasks",                         t.getTasks() != null ? t.getTasks() : List.of());
        dto.put("taskEveryMinutes",              t.getTaskEveryMinutes());
        dto.put("minTasksPerDay",                t.getMinTasksPerDay());
        dto.put("spinningWheelEntries",          t.getSpinningWheelEntries() != null ? t.getSpinningWheelEntries() : List.of());
        dto.put("spinsEveryMinutes",             t.getSpinsEveryMinutes());
        dto.put("minSpinsPerDay",                t.getMinSpinsPerDay());
        dto.put("requiresVerification",          t.isRequiresVerification());
        dto.put("taskMode",                      t.getTaskCardMode());
        dto.put("penaltyType",                   t.getPenaltyType());
        dto.put("penaltyValue",                  t.getPenaltyValue());
        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.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build();
        if (req.maxTimeInMinutes() == null || req.maxTimeInMinutes() < 1) return ResponseEntity.badRequest().build();

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

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

    @PutMapping("/{id}")
    public ResponseEntity<Map<String, Object>> update(@PathVariable("id") 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();
        TimeLockTemplateEntity t = opt.get();
        if (!t.getOwner().equals(myId)) return ResponseEntity.status(403).build();

        if (req.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build();
        if (req.maxTimeInMinutes() == null || req.maxTimeInMinutes() < 1) return ResponseEntity.badRequest().build();

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

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable("id") 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(TimeLockTemplateEntity t, TemplateRequest req) {
        t.setName(req.name());
        t.setMinTimeInMinutes(req.minTimeInMinutes());
        t.setMaxTimeInMinutes(req.maxTimeInMinutes());
        t.setEndTimeVisible(req.endTimeVisible());
        t.setHygineOpeningEveryMinites(req.hygineOpeningEveryMinites());
        t.setHygineOpeningDurationMinutes(req.hygineOpeningDurationMinutes());
        t.setTasks(req.tasks() != null ? req.tasks() : List.of());
        t.setTaskEveryMinutes(req.taskEveryMinutes());
        t.setMinTasksPerDay(req.minTasksPerDay());
        t.setSpinningWheelEntries(req.spinningWheelEntries() != null ? req.spinningWheelEntries() : List.of());
        t.setSpinsEveryMinutes(req.spinsEveryMinutes());
        t.setMinSpinsPerDay(req.minSpinsPerDay());
        t.setRequiresVerification(req.requiresVerification());
        t.setTaskMode(req.taskMode() != null ? req.taskMode() : TaskMode.RANDOM);
        t.setPenaltyType(req.penaltyType());
        t.setPenaltyValue(req.penaltyValue());
    }
}
