/*
 *  Copyright (c) 2025 John Ahlroos / Devsoap
 *
 *  Creative Commons Attribution-NoDerivatives 4.0 International Public License
 *
 *  By exercising the Licensed Rights (defined below), You accept and agree
 *  to be bound by the terms and conditions of this Creative Commons
 *  Attribution-NoDerivatives 4.0 International Public License ("Public
 *  License"). To the extent this Public License may be interpreted as a
 *  contract, You are granted the Licensed Rights in consideration of Your
 *  acceptance of these terms and conditions, and the Licensor grants You
 *  such rights in consideration of benefits the Licensor receives from
 *  making the Licensed Material available under these terms and
 *  conditions.
 *
 *  Refer to LICENSE file or https://creativecommons.org/licenses/by-nd/4.0 for full license.
 *
 */

package com.devsoap.tincheck.countries;

import com.devsoap.tincheck.tin.TinCountry;
import jakarta.inject.Singleton;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.stream.Collectors;

@Getter
@Singleton
@RequiredArgsConstructor
@ToString(of = {"countryCode", "countryName"})
public class Country_CZ implements TinCountry {

    private final String countryCode = "CZ";
    private final String countryName = "Czech Republic";

    @Override
    public String cleanTin(String tin) {
        return TinCountry.super.cleanTin(tin)
                .replace("/", "");
    }

    @Override
    public boolean formatCheck(String tin) {
        return  (tin.length() == 9 && StringUtils.isNumeric(tin)) ||
                (tin.length() == 10 && StringUtils.isNumeric(tin.substring(0,9)));
    }

    @Override
    public boolean logicCheck(String tin) {
        var month = Integer.parseUnsignedInt(tin.substring(2,4));
        if (month <= 12) {
            // nop
        } else if(month <= 32) {
            month -= 20;
        } else if(month <= 62) {
            month -= 50;
        } else if(month <= 82) {
            month -= 70;
        } else {
            return false;
        }
        return true;
    }

    @Override
    public String generate(LocalDate yearOfBirth, Gender gender, Random randomGenerator) {
        return randomGenerator.nextBoolean() ?
            generateFormat1(yearOfBirth, gender, randomGenerator) :
            generateFormat2(yearOfBirth, gender, randomGenerator);
    }

    private String generateFormat1(LocalDate yearOfBirth, Gender gender, Random randomGenerator) {
        var year = yearOfBirth.format(DateTimeFormatter.ofPattern("yy"));
        var month = StringUtils.leftPad(String.valueOf(gender == Gender.MALE ?
                yearOfBirth.getMonthValue() : yearOfBirth.getMonthValue() + 50), 2, '0');
        var day = yearOfBirth.format(DateTimeFormatter.ofPattern("dd"));
        var digits = yearOfBirth.getYear() <= 1953 ? "999" :
                randomGenerator.ints(3,0,9)
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining());
        return year + month + day + digits;
    }

    private String generateFormat2(LocalDate yearOfBirth, Gender gender, Random randomGenerator) {
        var year = yearOfBirth.format(DateTimeFormatter.ofPattern("yy"));
        var month = StringUtils.leftPad(String.valueOf(
                (gender == Gender.MALE) ?
                (randomGenerator.nextBoolean() ? 0 : 20) :
                (randomGenerator.nextBoolean() ? 50 : 70)
                + yearOfBirth.getMonthValue()),
                2, "0");
        var day = yearOfBirth.format(DateTimeFormatter.ofPattern("dd"));
        var digits = yearOfBirth.getYear() <= 1953 ? "999C" :
                randomGenerator.ints(3,0,9)
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining());
        return year + month + day + digits;
    }
}