package de.oaa.xxx.session.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.oaa.xxx.session.AufgabeAnzeige;
import de.oaa.xxx.session.Mitspieler;
import de.oaa.xxx.session.Session;
import de.oaa.xxx.session.SessionDurchfuehren;
import de.oaa.xxx.session.aufgaben.AufgabenList;
import de.oaa.xxx.session.entity.MitspielerEntity;
import de.oaa.xxx.session.entity.SessionEntity;
import de.oaa.xxx.session.repository.MitspielerRepository;
import de.oaa.xxx.session.repository.SessionRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.time.LocalDateTime;
import java.util.UUID;

@RestController
@RequestMapping("/session")
@Transactional
public class SessionController {

    private static final Logger LOGGER = LoggerFactory.getLogger(SessionController.class);

    private final SessionRepository sessionRepository;
    private final MitspielerRepository mitspielerRepository;
    private final ObjectMapper objectMapper;

    public SessionController(SessionRepository sessionRepository, MitspielerRepository mitspielerRepository,
                              ObjectMapper objectMapper) {
        this.sessionRepository = sessionRepository;
        this.mitspielerRepository = mitspielerRepository;
        this.objectMapper = objectMapper;
    }

    @GetMapping("/{sessionId}")
    public ResponseEntity<Session> getBySessionId(@PathVariable UUID sessionId) {
        return sessionRepository.findById(sessionId)
                .map(entity -> ResponseEntity.ok(toSession(entity)))
                .orElse(ResponseEntity.noContent().build());
    }

    @GetMapping
    public ResponseEntity<Session> getByUserId(@RequestParam UUID userId) {
        return sessionRepository.findByUserId(userId)
                .map(entity -> ResponseEntity.ok(toSession(entity)))
                .orElse(ResponseEntity.noContent().build());
    }

    @PostMapping
    public ResponseEntity<Void> create(@RequestBody Session session) {
        UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        SessionEntity entity = new SessionEntity();
        entity.setSessionId(UUID.randomUUID());
        entity.setUserId(userId);
        entity.setAufgabenAufAktuellemLevel(0);
        entity.setAufgabenProLevel(session.getAufgabenProLevel() != null ? session.getAufgabenProLevel() : 5);
        LocalDateTime now = LocalDateTime.now();
        entity.setLetzteAktivitaet(now);
        entity.setStartZeit(now);
        entity.setWahrscheinlichkeitSperre(session.getWahrscheinlichkeitSperre() != null ? session.getWahrscheinlichkeitSperre() : 10);
        entity.setWahrscheinlichkeitStrafe(session.getWahrscheinlichkeitStrafe() != null ? session.getWahrscheinlichkeitStrafe() : 10);
        entity.setZeitfaktorZeitstrafen(session.getZeitfaktorZeitstrafen() != null ? session.getZeitfaktorZeitstrafen() : 1.0);
        entity.setLevel(1);
        sessionRepository.save(entity);
        return ResponseEntity.created(
                ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(entity.getSessionId()).toUri()
        ).build();
    }

    @DeleteMapping
    public ResponseEntity<Void> deleteSession(@RequestBody Session session) {
        return sessionRepository.findById(session.getSessionId())
                .map(entity -> {
                    sessionRepository.delete(entity);
                    return ResponseEntity.accepted().<Void>build();
                })
                .orElse(ResponseEntity.noContent().build());
    }

    @PostMapping("/{sessionId}/aufgaben")
    public ResponseEntity<Void> setAufgaben(@RequestBody AufgabenList list, @PathVariable UUID sessionId) {
        try {
            if (list.size() > 1000) {
                return ResponseEntity.badRequest().build();
            }
            String aufgaben = objectMapper.writeValueAsString(list);
            SessionEntity session = sessionRepository.findById(sessionId).orElse(null);
            if (session == null) {
                return ResponseEntity.badRequest().build();
            }
            session.setAufgaben(aufgaben);
            sessionRepository.save(session);
            return ResponseEntity.accepted().build();
        } catch (Exception exception) {
            LOGGER.error(exception.getMessage(), exception);
            return ResponseEntity.internalServerError().build();
        }
    }

    @GetMapping("/{sessionId}/aufgaben/next")
    public ResponseEntity<AufgabeAnzeige> getNextAufgabe(@PathVariable UUID sessionId) {
        try {
            SessionEntity session = sessionRepository.findById(sessionId).orElse(null);
            if (session == null) {
                return ResponseEntity.badRequest().build();
            }
            session.setLetzteAktivitaet(LocalDateTime.now());
            AufgabeAnzeige next = new SessionDurchfuehren(session).getNext();
            return ResponseEntity.ok(next);
        } catch (Exception exception) {
            LOGGER.error(exception.getMessage(), exception);
            return ResponseEntity.internalServerError().build();
        }
    }

    @PostMapping("/{sessionId}/mitspieler")
    public ResponseEntity<Void> addMitspieler(@RequestBody Mitspieler mitspieler, @PathVariable UUID sessionId) {
        if (mitspieler.getName() == null || mitspieler.getGeschlecht() == null || mitspieler.getRollen() == null
                || mitspieler.getRollen().isEmpty() || mitspieler.getSpieltMit() == null || mitspieler.getSpieltMit().isEmpty()
                || mitspieler.getVerfuegbareWerkzeuge() == null || mitspieler.getVerfuegbareWerkzeuge().isEmpty()) {
            return ResponseEntity.badRequest().build();
        }
        SessionEntity session = sessionRepository.findById(sessionId).orElse(null);
        if (session == null) {
            return ResponseEntity.badRequest().build();
        }
        MitspielerEntity entity = new MitspielerEntity();
        entity.setMitspielerId(UUID.randomUUID());
        entity.setGeschlecht(mitspieler.getGeschlecht());
        entity.setName(mitspieler.getName());
        entity.setRollen(mitspieler.getRollen());
        entity.setSpieltMit(mitspieler.getSpieltMit());
        entity.setWerkzeuge(mitspieler.getVerfuegbareWerkzeuge());
        entity.setSession(session);
        mitspielerRepository.save(entity);
        return ResponseEntity.accepted().build();
    }

    private Session toSession(SessionEntity entity) {
        Session session = new Session();
        session.setSessionId(entity.getSessionId());
        session.setUserId(entity.getUserId());
        session.setAufgabenProLevel(entity.getAufgabenAufAktuellemLevel());
        session.setWahrscheinlichkeitSperre(entity.getWahrscheinlichkeitSperre());
        session.setWahrscheinlichkeitStrafe(entity.getWahrscheinlichkeitStrafe());
        session.setZeitfaktorZeitstrafen(entity.getZeitfaktorZeitstrafen());
        return session;
    }
}
