package de.champonthis.buntspecht.controller.admin;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.SplittableRandom;

import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.champonthis.buntspecht.model.QUser;
import de.champonthis.buntspecht.model.Turnover;
import de.champonthis.buntspecht.model.User;
import de.champonthis.buntspecht.repository.TurnoverRepository;
import de.champonthis.buntspecht.repository.UserRepository;

@RestController
@RequestMapping("/debug")
public class DebugController {

    private Logger logger = LoggerFactory.getLogger(DebugController.class);

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private TurnoverRepository turnoverRepository;

    SplittableRandom splittableRandom = new SplittableRandom();

    @PreAuthorize("hasRole('ROLE_DEBUG')")
    @GetMapping("/random")
    public void random(
            @RequestParam("users") Optional<Integer> usersParameter,
            @RequestParam("minEntries") Optional<Integer> minEntriesParameter,
            @RequestParam("maxEntries") Optional<Integer> maxEntriesParameter,
            @RequestParam("days") Optional<Integer> daysParameter) {
        logger.warn("start random generation");

        long userCount = userRepository.count(QUser.user.username.startsWith("Tätowier"));

        List<String> newUser = new ArrayList<>();

        for (long i = userCount + 1; i <= userCount + usersParameter.orElse(5); i++) {
            User user = new User();
            String username = (splittableRandom.nextBoolean() ? "Tätowiererin " : "Tätowierer ") + i;
            String name = "Random " + RandomStringUtils.randomAlphanumeric(splittableRandom.nextInt(4, 8));
            user.setUsername(username);
            user.setName(name);
            user.setPasswordHash(passwordEncoder.encode(username));
            user = userRepository.save(user);
            logger.trace("Created user: '" + username + "'");
            newUser.add(user.getUsername());
        }

        logger.info("Created " + usersParameter.orElse(5) + " users");

        Instant startInclusive = Instant.now().minus(daysParameter.orElse(350), ChronoUnit.DAYS);
        Instant endExclusive = Instant.now();

        for (String username : newUser) {
            long numEntries = splittableRandom.nextLong(minEntriesParameter.orElse(3), maxEntriesParameter.orElse(20));
            for (int i = 0; i < numEntries; i++) {
                Turnover turnover = new Turnover();
                turnover.setUsername(username);
                turnover.setCreated(randomDate(startInclusive, endExclusive));
                turnover.setUpdated(splittableRandom.nextBoolean() ? turnover.getCreated()
                        : randomDate(turnover.getCreated(), endExclusive));
                turnover.setCustomer(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(3, 10)));

                turnover.setMotif(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(5, 30)));

                turnover.setPrice(Float.valueOf(String.format("%.2f", splittableRandom.nextFloat(0.01f, 2000f))));

                if (splittableRandom.nextBoolean()) {
                    turnover.setTimeInvestment(
                            Float.valueOf(String.format("%.2f", splittableRandom.nextFloat(0.01f, 20f))));
                }

                if (splittableRandom.nextBoolean()) {
                    turnover.setRemark(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(10, 50)));
                }

                if (splittableRandom.nextInt(5) < 3) {
                    turnover.setMaterialConsumption(
                            RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(10, 250)));
                }

                turnover = turnoverRepository.save(turnover);
                logger.trace("Created turnover: '" + turnover.getId() + "'");
            }
            logger.info("Created " + numEntries + " turnovers of '" + username + "'");
        }

        logger.warn("finished random generation");
    }

    protected Instant randomDate(Instant startInclusive, Instant endExclusive) {
        long startSeconds = startInclusive.getEpochSecond();
        long endSeconds = endExclusive.getEpochSecond();
        long random = splittableRandom.nextLong(startSeconds, endSeconds);

        return Instant.ofEpochSecond(random);
    }
}
