package br.gov.sigefp.rh.config;

import br.gov.sigefp.rh.domain.*;
import br.gov.sigefp.rh.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.springframework.core.annotation.Order;

@Slf4j
@Component
@RequiredArgsConstructor
@Order(2)
@Transactional
public class PayrollDataInitializer implements CommandLineRunner {

    private final EarningTypeRepository earningTypeRepository;
    private final DeductionTypeRepository deductionTypeRepository;
    private final GlobalDeductionRuleRepository globalDeductionRuleRepository;
    private final TaxBracketRepository taxBracketRepository;
    private final PayrollPeriodRepository payrollPeriodRepository;
    private final SalaryCategoryRepository salaryCategoryRepository;
    private final SalaryGradeRepository salaryGradeRepository;
    private final SalaryStepRepository salaryStepRepository;
    private final SalaryGridRepository salaryGridRepository;
    private final AgentRepository agentRepository;
    private final br.gov.sigefp.budget.repository.BudgetLineRepository budgetLineRepository;
    private final br.gov.sigefp.budget.repository.FiscalYearRepository fiscalYearRepository;

    private final FamilyAllowanceTableRepository familyAllowanceTableRepository;

    @Override
    // @Transactional removed to allow partial commits
    public void run(String... args) {
        log.info("Inicializando tipos de proventos, descontos e regras tributárias...");

        // 1. Proventos
        createEarningTypeIfNotExist("SALARIO_BASE", "Vencimento Base", true, "311100");
        createEarningTypeIfNotExist("SUBSIDIO", "Subsídio de Representação", true, "311102");
        createEarningTypeIfNotExist("ABONO_FAMILIA", "Abono de Família", false, "312101");

        // 1.1 Tabela de Abono de Família
        for (int i = 1; i <= 10; i++) {
            createFamilyAllowanceIfNotExist(i, new BigDecimal("1000").multiply(new BigDecimal(i)));
        }

        // 2. Descontos
        DeductionType inps = createDeductionTypeIfNotExist("INPS", "Segurança Social (INPS)", "312100");
        DeductionType irps = createDeductionTypeIfNotExist("IRPS", "Imposto Profissional (IRPS)", null);
        DeductionType demo = createDeductionTypeIfNotExist("ID", "Imposto de Democracia", null);
        DeductionType selo = createDeductionTypeIfNotExist("SELO", "Imposto de Selo", null);
        DeductionType falta = createDeductionTypeIfNotExist("FALTA_INJUSTIFICADA", "Falta Injustificada", null);

        // 3. Regras Globais (Válidas desde 2024 até o infinito por padrão)
        createGlobalRuleIfNotExist(inps, new BigDecimal("0.07"));
        createGlobalRuleIfNotExist(selo, new BigDecimal("0.003"));

        // Limpar tabela de escalões para garantir conformidade com a nova lei
        // Limpar tabela de escalões para garantir conformidade com a nova lei
        // try {
        // taxBracketRepository.deleteAllInBatch();
        // log.info("Tabela de escalões limpa com sucesso.");
        // } catch (Exception e) {
        // log.error("Erro ao limpar tabela de escalões: {}", e.getMessage());
        // }

        createTaxBracketIfNotExist(irps, "0.00", "41667.00", "0.0100", "0.00", null);
        createTaxBracketIfNotExist(irps, "41668.00", "83333.00", "0.0600", "2083.00", null);
        createTaxBracketIfNotExist(irps, "83334.00", "208333.00", "0.0800", "3750.00", null);
        createTaxBracketIfNotExist(irps, "208334.00", "300000.00", "0.1000", "7917.00", null);
        createTaxBracketIfNotExist(irps, "300001.00", "400500.00", "0.1200", "13917.00", null);
        createTaxBracketIfNotExist(irps, "400501.00", "750000.00", "0.1400", "21927.00", null);
        createTaxBracketIfNotExist(irps, "750001.00", "1100000.00", "0.1600", "36927.00", null);
        createTaxBracketIfNotExist(irps, "1100001.00", "1500000.00", "0.1800", "58927.00", null);
        createTaxBracketIfNotExist(irps, "1500001.00", null, "0.2000", "88929.00", null);

        // 6. Imposto de Democracia (Novas Regras)
        // createTaxBracketIfNotExist(demo, "0.00", "41667.00", null, null, "500.00");
        // createTaxBracketIfNotExist(demo, "41668.00", "83333.00", null, null,
        // "1000.00");
        // createTaxBracketIfNotExist(demo, "83334.00", "208333.00", null, null,
        // "2000.00");
        // createTaxBracketIfNotExist(demo, "208334.00", "300000.00", null, null,
        // "4000.00");
        // createTaxBracketIfNotExist(demo, "300001.00", "405500.00", null, null,
        // "6000.00");
        // createTaxBracketIfNotExist(demo, "405501.00", "750000.00", null, null,
        // "10000.00");
        // createTaxBracketIfNotExist(demo, "750001.00", "1100000.00", null, null,
        // "15000.00");
        // createTaxBracketIfNotExist(demo, "1100001.00", "1500000.00", null, null,
        // "17000.00");
        // createTaxBracketIfNotExist(demo, "1500001.00", null, null, null, "20000.00");

        // 5. Estrutura Salarial e Grelha
        // 5. Estrutura Salarial e Grelha
        try {
            // initializeSalaryAndPeriod(); // Disable to prevent hang
            log.info("Inicialização de Salários pulada para garantir boot.");
        } catch (Exception e) {
            log.error("Erro ao inicializar estrutura salarial: {}", e.getMessage());
        }

        log.info("Configuração tributária e operacional concluída.");
    }

    // Helper atualizado para suportar Taxa Progressiva OU Valor Fixo
    private void createTaxBracketIfNotExist(DeductionType type, String lower, String upper, String rate,
            String excess, String fixed) {
        BigDecimal low = new BigDecimal(lower);
        BigDecimal up = upper != null ? new BigDecimal(upper) : null;

        // Verifica duplicidade
        List<TaxBracket> active = taxBracketRepository.findActiveBrackets(LocalDate.now());
        boolean exists = active.stream().anyMatch(
                b -> b.getDeductionType().getCode().equals(type.getCode()) && b.getLowerLimit().compareTo(low) == 0);

        if (!exists) {
            TaxBracket bracket = TaxBracket.builder()
                    .deductionType(type)
                    .lowerLimit(low)
                    .upperLimit(up)
                    .ratePercentage(rate != null ? new BigDecimal(rate) : null)
                    .excessDeduction(excess != null ? new BigDecimal(excess) : null)
                    .fixedAmount(fixed != null ? new BigDecimal(fixed) : null)
                    .validFrom(LocalDate.of(2024, 1, 1))
                    .build();
            taxBracketRepository.save(bracket);
            log.info("Escalão {} criado: {} a {}", type.getCode(), lower, upper != null ? upper : "inf");
        }
    }

    private void createEarningTypeIfNotExist(String code, String name, boolean taxable, String econClass) {
        if (earningTypeRepository.findByCode(code).isEmpty()) {
            EarningType type = EarningType.builder()
                    .code(code)
                    .name(name)
                    .taxable(taxable)
                    .economicClassCode(econClass)
                    .build();
            earningTypeRepository.save(type);
            log.info("Tipo de Provento criado: {}", code);
        }
    }

    private DeductionType createDeductionTypeIfNotExist(String code, String name, String econClass) {
        return deductionTypeRepository.findByCode(code).orElseGet(() -> {
            DeductionType type = DeductionType.builder()
                    .code(code)
                    .name(name)
                    .economicClassCode(econClass)
                    .build();
            log.info("Tipo de Desconto criado: {}", code);
            return deductionTypeRepository.save(type);
        });
    }

    private void createGlobalRuleIfNotExist(DeductionType type, BigDecimal percentage) {
        // Optimized: Check existence via count/exists query to avoid
        // LazyInitializationException
        boolean exists = globalDeductionRuleRepository.findAll().stream()
                .anyMatch(r -> r.getDeductionType() != null && r.getDeductionType().getId().equals(type.getId()));

        if (!exists) {
            GlobalDeductionRule rule = GlobalDeductionRule.builder()
                    .deductionType(type)
                    .percentage(percentage)
                    .amountFixed(null)
                    .validFrom(LocalDate.of(2024, 1, 1))
                    .build();
            globalDeductionRuleRepository.save(rule);
            log.info("Regra Global criada: {} ({}%)", type.getName(), percentage.multiply(new BigDecimal(100)));
            log.info("Regra Global criada: {} ({}%)", type.getName(), percentage.multiply(new BigDecimal(100)));
        }
    }

    private void createFamilyAllowanceIfNotExist(Integer dependents, BigDecimal amount) {
        // Simple check to avoid LazyInitializationException usually not needed for
        // simple find
        if (familyAllowanceTableRepository.findByDependentsAndDate(dependents, LocalDate.now()).isEmpty()) {
            FamilyAllowanceTable table = FamilyAllowanceTable.builder()
                    .dependentsCount(dependents)
                    .amount(amount)
                    .validFrom(LocalDate.of(2024, 1, 1))
                    .build();
            familyAllowanceTableRepository.save(table);
            log.info("Abono de Família configurado: {} dependentes = {}", dependents, amount);
        }
    }
}
