package com.devsoap.tincheck;

import com.devsoap.tincheck.services.TinCheckService;
import com.devsoap.tincheck.tin.TinCountry;
import com.devsoap.tincheck.tin.TinGenerator;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.reflections.Reflections;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

@Slf4j
public class TinCountryTest {

    @ParameterizedTest(name = "{arguments}")
    @MethodSource("countries")
    public void testTinValidationAndGeneration(TinCountry country) {
        var random = new Random(42);

        var service = new TinCheckService(List.of(country), new Random());
        for (var i=0; i<50; i++) {
            var date = LocalDate.of(random.nextInt(1854,2030),random.nextInt(1,12), random.nextInt(1,28));
            var tin = service.generate(country.getCountryCode(), date, random.nextBoolean() ? TinGenerator.Gender.MALE: TinGenerator.Gender.FEMALE).value();
            log.info("Generated TIN {} for country {}", tin, country.getCountryCode());
            assertEquals("valid", service.validate(country.getCountryCode(), tin).result());
        }
    }

    private static Stream<Arguments> countries() throws Exception {
        var reflections = new Reflections("com.devsoap.tincheck.countries");
        var countryClasses = reflections.getSubTypesOf(TinCountry.class);
        var countryInstances = new ArrayList<TinCountry>();
        for (Class<? extends TinCountry> countryClazz : countryClasses) {
            countryInstances.add(countryClazz.getConstructor().newInstance());
        }
        return countryInstances.stream().sorted().map(Arguments::of);
    }
}