package br.gov.sigefp.api.seeder;

import br.gov.sigefp.budget.domain.*;
import br.gov.sigefp.budget.repository.*;
import br.gov.sigefp.org.domain.*;
import br.gov.sigefp.org.repository.*;
import br.gov.sigefp.rh.domain.*; // Added
import br.gov.sigefp.rh.repository.*; // Added
import br.gov.sigefp.treasury.repository.PaymentOrderRepository;
import br.gov.sigefp.treasury.repository.CashAccountRepository;
import br.gov.sigefp.common.repository.BankRepository; // Added import
import org.springframework.jdbc.core.JdbcTemplate;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

import org.springframework.core.annotation.Order;

// @Component
@RequiredArgsConstructor
@Slf4j
@Order(1)
public class OgeSeeder implements CommandLineRunner {

    private final JdbcTemplate jdbcTemplate; // Injected
    private final BankRepository bankRepository; // Injected
    private final MinistryRepository ministryRepository;
    private final OrgUnitRepository orgUnitRepository;
    private final PositionRepository positionRepository; // Injected
    private final BudgetLineRepository budgetLineRepository;
    private final BudgetEntryRepository budgetEntryRepository;
    private final BudgetExecutionRepository budgetExecutionRepository;
    private final PaymentOrderRepository paymentOrderRepository;
    private final CashAccountRepository cashAccountRepository;
    private final EconomicClassificationRepository economicClassificationRepository;
    private final FiscalYearRepository fiscalYearRepository;
    private final ObjectMapper objectMapper;

    // RH Repositories
    private final CareerRegimeRepository careerRegimeRepository;
    private final SalaryCategoryRepository salaryCategoryRepository;
    private final SalaryGradeRepository salaryGradeRepository;
    private final SalaryStepRepository salaryStepRepository;
    private final SalaryGridRepository salaryGridRepository;

    @Override
    // Removed @Transactional to allow partial commits (cleanup) even if seeding
    // fails
    public void run(String... args) throws Exception {
        log.info("Iniciando verificação de Seed do OGE 2025...");

        // 0. Limpar dados anteriores (Nuclear Option para dev)
        cleanup();

        // 1. Seed Reference Data
        seedRegimes(); // New Step
        seedBanks(); // Temporarily disabled to fix build
        seedEconomicClassifications();

        // 2. Garantir Ano Fiscal 2025
        FiscalYear fiscalYear = ensureFiscalYear2025();

        // 3. Ler JSON e Seed Ministérios/Linhas
        try {
            ClassPathResource resource = new ClassPathResource("seeds/oge_2025.json");
            if (!resource.exists()) {
                log.warn("Arquivo seeds/oge_2025.json não encontrado. Pulando seed.");
                return;
            }

            InputStream inputStream = resource.getInputStream();
            List<OgeItemDTO> items = objectMapper.readValue(inputStream, new TypeReference<List<OgeItemDTO>>() {
            });

            log.info("Processando Ministérios (Passo 1/2)...");
            for (OgeItemDTO item : items) {
                if (!"ORG_UNIT".equals(item.getType())) {
                    try {
                        seedItem(item, fiscalYear);
                    } catch (Exception e) {
                        log.error("Erro ao processar Ministério: " + item.getName(), e);
                    }
                }
            }

            log.info("Processando Unidades Organizacionais (Passo 2/2)...");
            for (OgeItemDTO item : items) {
                if ("ORG_UNIT".equals(item.getType())) {
                    try {
                        seedItem(item, fiscalYear);
                    } catch (Exception e) {
                        log.error("Erro ao processar Unidade Organizacional: " + item.getName(), e);
                    }
                }
            }

            log.info("Seed OGE 2025 concluído com sucesso!");

            // 4. Seed Positions (Cargos/Funções Completos)
            seedAllPositions();

            // 5. Seed Salary Grid
            seedSalaryGrid();

        } catch (Exception e) {
            log.error("Erro ao executar seed do OGE 2025", e);
        }
    }

    private void seedRegimes() {
        log.info("Seeding Regimes de Carreira...");

        createRegime("REG-GERAL", "Regime Geral", "Quadro comum da Função Pública");
        createRegime("REG-SAUDE", "Regime Especial - Saúde", "Carreiras Médica, Enfermagem e Técnicos de Saúde");
        createRegime("REG-EDUCACAO", "Regime Especial - Educação", "Pessoal Docente e Investigação");
        createRegime("REG-JUSTICA", "Regime Especial - Justiça", "Magistratura Judicial e Ministério Público");
        createRegime("REG-MILITAR", "Regime Militar/Paramilitar", "Forças Armadas e de Segurança");
    }

    private void createRegime(String code, String name, String description) {
        if (careerRegimeRepository.findByCode(code).isEmpty()) {
            careerRegimeRepository.save(CareerRegime.builder()
                    .code(code)
                    .name(name)
                    .description(description)
                    .build());
        }
    }

    private void seedAllPositions() {
        log.info("Iniciando Seed Completo de Cargos e Funções (Multi-Setorial)...");
        seedSovereigntyPositions();
        seedEducationPositions();
        seedJusticePositions();
        seedMilitaryPositions();
        seedHealthPositions();
        seedAdministrativePositions();
    }

    // [Previous Position Seeding Methods 1-6 remain unchanged...]
    // For brevity in this tool call, I'm skipping re-pasting them unless I touch
    // them.
    // Wait, replace_file_content replaces a block. I need to be careful not to
    // delete lines between run() and seedSalaryGrid().
    // I will target specific blocks or ensure the context is correct.

    // ... [Lines 126-232 omitted for brevity as they are unchanged] ...

    // Changing seedSalaryGrid implementation
    private void seedSalaryGrid() {
        log.info("Seeding Grelha Salarial...");

        // Fetch Regimes
        CareerRegime regGeral = careerRegimeRepository.findByCode("REG-GERAL").orElseThrow();
        CareerRegime regSaude = careerRegimeRepository.findByCode("REG-SAUDE").orElseThrow();
        CareerRegime regEducacao = careerRegimeRepository.findByCode("REG-EDUCACAO").orElseThrow();
        CareerRegime regJustica = careerRegimeRepository.findByCode("REG-JUSTICA").orElseThrow();
        CareerRegime regMilitar = careerRegimeRepository.findByCode("REG-MILITAR").orElseThrow();

        // 1. Create Categories linked to Regimes

        // Categoria Geral
        SalaryCategory catGeral = salaryCategoryRepository.findByCode("Geral")
                .orElseGet(() -> SalaryCategory.builder().code("Geral").name("Tabela Salarial Geral 2025").build());
        catGeral.setRegime(regGeral);
        catGeral = salaryCategoryRepository.save(catGeral);

        // Categoria Saúde
        SalaryCategory catSaude = salaryCategoryRepository.findByCode("Saude")
                .orElseGet(() -> SalaryCategory.builder().code("Saude").name("Tabela Especial da Saúde").build());
        catSaude.setRegime(regSaude);
        catSaude = salaryCategoryRepository.save(catSaude);

        // Categoria Educação
        SalaryCategory catEducacao = salaryCategoryRepository.findByCode("Educacao")
                .orElseGet(
                        () -> SalaryCategory.builder().code("Educacao").name("Estatuto da Carreira Docente").build());
        catEducacao.setRegime(regEducacao);
        catEducacao = salaryCategoryRepository.save(catEducacao);

        // Categoria Justiça
        SalaryCategory catJustica = salaryCategoryRepository.findByCode("Justica")
                .orElseGet(() -> SalaryCategory.builder().code("Justica").name("Estatuto da Magistratura").build());
        catJustica.setRegime(regJustica);
        catJustica = salaryCategoryRepository.save(catJustica);

        // Categoria Militar
        SalaryCategory catMilitar = salaryCategoryRepository.findByCode("Militar")
                .orElseGet(() -> SalaryCategory.builder().code("Militar").name("Estatuto Militar / Forças de Segurança")
                        .build());
        catMilitar.setRegime(regMilitar);
        catMilitar = salaryCategoryRepository.save(catMilitar);

        // Data Format: {Code, Description, BaseSalary}
        // Load Salary Grid from JSON
        try {
            ClassPathResource gridResource = new ClassPathResource("seeds/salary_grid.json");
            if (gridResource.exists()) {
                InputStream gridStream = gridResource.getInputStream();
                List<SalaryGridItemDTO> gridItems = objectMapper.readValue(gridStream,
                        new TypeReference<List<SalaryGridItemDTO>>() {
                        });

                log.info("Seeding " + gridItems.size() + " salary grid items from JSON...");

                for (SalaryGridItemDTO item : gridItems) {
                    String code = item.getCode();
                    String name = item.getName();
                    BigDecimal baseSalary = new BigDecimal(item.getBaseSalary());

                    // Use name directly, JSON currently be correct from the converter
                    String correctedName = item.getName();

                    // Determine Category
                    SalaryCategory targetCategory;

                    if (code.startsWith("5") || code.startsWith("2F") || code.startsWith("2G")) {
                        targetCategory = catSaude;
                    } else if (code.startsWith("AA") || code.startsWith("AC") || code.startsWith("BC")
                            || code.startsWith("MIL")) {
                        targetCategory = catMilitar;
                    } else if (correctedName.contains("Juiz") || correctedName.contains("Procurador")
                            || correctedName.contains("Magistrado") || code.equals("60")) {
                        targetCategory = catJustica;
                    } else if (correctedName.contains("Professor") || correctedName.contains("Docente")
                            || code.startsWith("ED")) {
                        targetCategory = catEducacao;
                    } else {
                        targetCategory = catGeral;
                    }

                    // Create Grade
                    SalaryCategory finalTargetCategory = targetCategory;
                    String finalName = correctedName;
                    SalaryGrade grade = salaryGradeRepository.findByCode(code)
                            .orElseGet(() -> salaryGradeRepository.save(SalaryGrade.builder()
                                    .category(finalTargetCategory)
                                    .code(code)
                                    .name(finalName)
                                    .build()));

                    // Update category if it exists but mismatched (optional)
                    if (code.equals("0P01")) {
                        log.info("SEEDING 0P01: Base={}, Sub={}, Gross={}", baseSalary, item.getSubsidy(),
                                item.getGross());
                    }
                    if (!grade.getCategory().getId().equals(targetCategory.getId())) {
                        grade.setCategory(targetCategory);
                        salaryGradeRepository.save(grade);
                    }

                    // Create Step 1 for this Grade
                    SalaryStep step = salaryStepRepository.findByGradeAndStepNumber(grade, 1)
                            .orElseGet(() -> salaryStepRepository.save(SalaryStep.builder()
                                    .grade(grade)
                                    .stepNumber(1)
                                    .build()));

                    // Create or Update Grid Value (Active for 2025)
                    SalaryGrid grid = salaryGridRepository.findByStepId(step.getId())
                            .stream().findFirst()
                            .orElse(SalaryGrid.builder()
                                    .step(step)
                                    .validFrom(LocalDate.of(2025, 1, 1))
                                    .build());

                    // Always update amounts
                    grid.setBaseAmount(baseSalary);
                    grid.setSubsidyAmount(
                            item.getSubsidy() != null ? new BigDecimal(item.getSubsidy()) : BigDecimal.ZERO);
                    grid.setGrossAmount(item.getGross() != null ? new BigDecimal(item.getGross()) : baseSalary);

                    salaryGridRepository.save(grid);
                }
            } else {
                log.warn("seeds/salary_grid.json NOT FOUND.");
            }
        } catch (Exception e) {
            log.error("Failed to seed salary grid from JSON", e);
        }
    }

    // 1. Órgãos de Soberania e Direção Superior
    private void seedSovereigntyPositions() {
        log.info("Seeding Cargos de Soberania...");

        // Mapeamento de Órgãos Específicos
        seedPositionsForUnit("GW-COA-2",
                List.of("Presidente da República", "Chefe de Gabinete do PR", "Assessor do PR",
                        "Secretária Particular do PR"));
        seedPositionsForUnit("GW-COA-1",
                List.of("Presidente da Assembleia", "Deputado", "Chefe de Gabinete da ANP", "Assessor da ANP"));
        seedPositionsForUnit("GW-COA-3",
                List.of("Primeiro-Ministro", "Chefe de Gabinete do PM", "Assessor do PM", "Secretária do PM"));
        seedPositionsForUnit("GW-COA-4", List.of("Presidente do STJ", "Vice-Presidente do STJ",
                "Juiz Conselheiro do STJ", "Secretário Judicial"));
        seedPositionsForUnit("GW-COA-5", List.of("Presidente do Tribunal de Contas", "Vice-Presidente do TC",
                "Juiz Conselheiro do TC", "Contador Chefe"));
        seedPositionsForUnit("GW-COA-6",
                List.of("Procurador-Geral da República", "Vice-PGR", "Procurador-Geral Adjunto"));

        // Cargos de Direção Superior Genéricos (Aplicar a todos os Ministérios)
        List<Ministry> allMinistries = ministryRepository.findAll();
        List<String> highLevelRoles = List.of(
                "Ministro", "Secretário de Estado", "Secretário-Geral", "Inspetor Geral",
                "Diretor Geral", "Diretor de Serviço", "Chefe de Gabinete", "Assessor");

        for (Ministry min : allMinistries) {
            orgUnitRepository.findByCode(min.getCode()).ifPresent(cabinet -> {
                for (String role : highLevelRoles) {
                    createPosition(cabinet, generateSlug(role), role, "Direção Superior");
                }
            });
        }
    }

    // 2. Educação e Ensino
    private void seedEducationPositions() {
        log.info("Seeding Cargos de Educação...");
        List<String> eduRoles = List.of(
                "Professor B", "Delegado Regional de Ensino", "Diretor de Ensino Secundário",
                "Diretor de Ensino Básico", "Enfermeiro Professor (Escalão 5)",
                "Enfermeiro Professor (Escalão 4)", "Enfermeiro Professor (Escalão 3)",
                "Enfermeiro Professor (Escalão 2)");
        seedPositionsForUnit("GW-COA-15", eduRoles); // Ministério da Educação
        seedPositionsForUnit("GW-COA-72", eduRoles); // Ensino Superior
    }

    // 3. Setor da Justiça e Investigação
    private void seedJusticePositions() {
        log.info("Seeding Cargos de Justiça...");
        List<String> justiceRoles = List.of(
                "Diretor Nacional da Polícia Judiciária", "Diretor Nacional Adjunto da PJ",
                "Inspetor Coordenador de Nível", "Diretor de Centro Prisional",
                "Perito Superior Criminal (Nível III)", "Sub-Inspetor",
                "Juiz de Direito", "Juiz Secretário-Licenciado", "Delegado (Procuradoria)",
                "Agente de Investigação Criminal (Nível I)", "Chefe de Guarda Prisional",
                "Escrivão de Direito", "Escrivão Adjunto", "Oficial de Delegacia",
                "Chefe de Serviços de Segurança Interna", "Pessoal de Segurança Interna");
        seedPositionsForUnit("GW-COA-6", justiceRoles); // Ministério da Justiça
        seedPositionsForUnit("GW-COA-10", List.of("Comissário", "Agente de Polícia", "Oficial de Polícia")); // Interior
    }

    // 4. Carreira Militar
    private void seedMilitaryPositions() {
        log.info("Seeding Cargos Militares...");
        List<String> militaryRoles = List.of(
                "General", "Tenente-General", "Major-General", "Brigadeiro-General",
                "Coronel", "Tenente-Coronel", "Major", "Capitão", "Tenente", "Alferes",
                "Sargento-Mor", "Sargento", "1º Sargento", "2º Sargento", "Furiel",
                "Cabo", "Soldado");
        seedPositionsForUnit("GW-COA-9", militaryRoles); // Defesa Nacional
    }

    // 5. Setor da Saúde (Updated with User List + Previous Grid)
    private void seedHealthPositions() {
        log.info("Seeding Cargos de Saúde...");
        List<String> healthRoles = List.of(
                "Médico Especialista Hospitalar Principal", "Médico Especialista Hospitalar",
                "Assistente Clínico Geral", "Médico", "Técnico Superior Equiparado a Médico",
                "Enfermeiro Superior", "Técnico Superior de Assistência Social",
                "Enfermeiro Especialista", "Enfermeiro Parteira", "Enfermeiro Monitor",
                "Enfermeiro Geral", "Técnico de Diagnóstico e Terapêutica Especialista",
                "Técnico de Diagnóstico e Terapêutica Geral", "Auxiliar de Saúde", "Diretor Regional de Saúde");
        seedPositionsForUnit("GW-COA-18", healthRoles); // Saúde
    }

    // 6. Áreas Administrativa, Técnica e Outros (Genérico para TODAS as Unidades)
    private void seedAdministrativePositions() {
        log.info("Seeding Cargos Administrativos Gerais...");
        List<String> adminRoles = List.of(
                "Técnico Especialista Principal", "Assessor Técnico",
                "Técnico Superior de 1ª Classe", "Técnico Superior de 2ª Classe", "Técnico Superior Estagiário",
                "Técnico de 1ª Classe", "Técnico de 2ª Classe",
                "Técnico Profissional Especialista", "Técnico Profissional de 1ª Classe",
                "Chefe de Repartição", "Chefe de Secção",
                "1º Oficial", "2º Oficial", "3º Oficial", "Oficial de Diligência",
                "Assistente Administrativo Especialista", "Assistente Administrativo Principal",
                "Assistente Administrativo",
                "Aspirante", "Escriturário Dactilógrafo", "Motorista", "Auxiliar", "Pessoal de Limpeza");

        // Aplica a TODAS as OrgUnits do sistema (Ministérios e Secretarias)
        List<OrgUnit> allUnits = orgUnitRepository.findAll();
        for (OrgUnit unit : allUnits) {
            for (String role : adminRoles) {
                createPosition(unit, generateSlug(role), role, "Administrativo");
            }
        }
    }

    // Helper Methods
    private void seedPositionsForUnit(String orgUnitCode, List<String> roles) {
        orgUnitRepository.findByCode(orgUnitCode).ifPresent(unit -> {
            for (String role : roles) {
                createPosition(unit, generateSlug(role), role, "Carreira Específica");
            }
        });
    }

    private String generateSlug(String text) {
        if (text == null)
            return "UNK";

        // Normalize and remove accents
        String normalized = text.replaceAll("[ÁÀÃÂÄ]", "A")
                .replaceAll("[ÉÈÊË]", "E")
                .replaceAll("[ÍÌÎÏ]", "I")
                .replaceAll("[ÓÒÕÔÖ]", "O")
                .replaceAll("[ÚÙÛÜ]", "U")
                .replaceAll("[Ç]", "C")
                .replaceAll("[áàãâä]", "a")
                .replaceAll("[éèêë]", "e")
                .replaceAll("[íìîï]", "i")
                .replaceAll("[óòõôö]", "o")
                .replaceAll("[úùûü]", "u")
                .replaceAll("[ç]", "c");

        // Convert to CamelCase/PascalCase
        StringBuilder sb = new StringBuilder();
        String[] parts = normalized.split("\\s+");
        for (String part : parts) {
            String p = part.replaceAll("[^a-zA-Z0-9]", "");
            if (p.length() > 0) {
                sb.append(p.substring(0, 1).toUpperCase());
                if (p.length() > 1) {
                    sb.append(p.substring(1).toLowerCase());
                }
            }
        }

        String slug = sb.toString();

        if (slug.length() > 30) {
            slug = slug.substring(0, 30);
        }
        return slug;
    }

    private void createPosition(OrgUnit orgUnit, String suffix, String title, String level) {
        String code = orgUnit.getCode() + "-" + suffix;
        // Ensure uniqueness check matches the entity constraint
        if (positionRepository.findByCode(code).isEmpty()) {
            positionRepository.save(Position.builder()
                    .orgUnit(orgUnit)
                    .code(code)
                    .title(title)
                    .level(level)
                    .isActive(true)
                    .build());
        }
    }

    private void cleanup() {
        log.info("Limpando base de dados do Orçamento (NUCLEAR TRUNCATE)...");
        try {
            // PostgreSQL specific: TRUNCATE with CASCADE to clean everything efficiently
            // Order doesn't matter with CASCADE, but listing helps clarity
            String sql = "TRUNCATE TABLE " +
                    "payment_order, " +
                    "cash_account, " +
                    "budget_execution, " +
                    "budget_entry, " +
                    "budget_line, " +
                    "position, " +
                    "org_unit, " +
                    "ministry, " +
                    "economic_classification, " +
                    "bank, " +
                    "salary_grid, " +
                    "salary_step, " +
                    "salary_grade, " +
                    "salary_category, " +
                    "career_regime " +
                    "CASCADE";

            jdbcTemplate.execute(sql);
            log.info("Limpeza NUCLEAR realizada com sucesso.");
        } catch (Exception e) {
            log.error("Falha na limpeza NUCLEAR. Tentando fallback para DELETE.", e);
            // Fallback just in case, though TRUNCATE should work on Postgres
            jdbcTemplate.execute("DELETE FROM payment_order");
            jdbcTemplate.execute("DELETE FROM cash_account");
            jdbcTemplate.execute("DELETE FROM budget_execution");
            jdbcTemplate.execute("DELETE FROM budget_entry");
            jdbcTemplate.execute("DELETE FROM budget_line");
            jdbcTemplate.execute("DELETE FROM position");
            jdbcTemplate.execute("DELETE FROM org_unit");
            jdbcTemplate.execute("DELETE FROM ministry");
            jdbcTemplate.execute("DELETE FROM economic_classification");
            jdbcTemplate.execute("DELETE FROM bank");
            jdbcTemplate.execute("DELETE FROM salary_grid");
            jdbcTemplate.execute("DELETE FROM salary_step");
            jdbcTemplate.execute("DELETE FROM salary_grade");
            jdbcTemplate.execute("DELETE FROM salary_category");
            jdbcTemplate.execute("DELETE FROM career_regime");
        }
    }

    private void seedBanks() {
        log.info("Seeding Bancos...");
        createBank("BCEAO", "Banco Central dos Estados da África Ocidental", "001");
        createBank("BAO", "Banco da África Ocidental", "002");
        createBank("BDU", "Banco da União", "003");
        createBank("BIA", "Banco Internacional da África", "004");
        createBank("ECOBANK", "Ecobank Guiné-Bissau", "005");
        createBank("ORABANK", "Orabank Guiné-Bissau", "006");
        createBank("TESOURO", "Tesouro Público", "000"); // Conta Única do Tesouro (Internal)
    }

    private void createBank(String code, String name, String bankCode) {
        if (bankRepository.findByCode(code).isEmpty()) {
            bankRepository.save(br.gov.sigefp.common.domain.Bank.builder()
                    .code(code)
                    .name(name)
                    .swiftCode(bankCode) // Map numeric code to swiftCode for now
                    .build());
        }
    }

    private void seedEconomicClassifications() {
        log.info("Seeding Classificações Econômicas...");

        // Receitas
        createClassification("7111", "Contribuição predial (Urbana e Rústica)", "REVENUE", "010101");
        createClassification("712", "Imposto profissional (Função Pública e Outros)", "REVENUE", "010102");
        createClassification("7143", "Imposto de Democracia", "REVENUE", "010106");
        createClassification("7151", "Imposto Geral s/Venda (IGV/IVA)", "REVENUE", "020301");
        createClassification("7161", "Impostos de selo e estampilhas", "REVENUE", "020401");
        createClassification("7171", "Direitos de importação", "REVENUE", "020101");
        createClassification("7182", "Imposto extraordinário", "REVENUE", "020103");
        createClassification("7199", "Outros (Impostos Comunitários)", "REVENUE", "020199");
        createClassification("72143", "Licenças de Pescas", "REVENUE", "030101");
        createClassification("7232", "Juros do Sector Público", "REVENUE", "040401");
        createClassification("73124", "Segurança Social", "REVENUE", "050204");
        createClassification("72931", "Venda de serviços pelas administrações públicas", "REVENUE", "060301");

        // Despesas - Pessoal
        createClassification("6111", "Salários do pessoal do quadro", "EXPENSE", null);
        createClassification("6112", "Salários do pessoal em qualquer outra situação", "EXPENSE", null);
        createClassification("6135", "Saúde e Indemnizações", "EXPENSE", null);
        createClassification("6139", "Outras Gratificações", "EXPENSE", null);
        createClassification("6151", "Encargos com saúde", "EXPENSE", null);

        // Despesas - Funcionamento
        createClassification("6212", "Combustíveis e lubrificantes", "EXPENSE", null);
        createClassification("6213", "Consumo de secretaria", "EXPENSE", null);
        createClassification("6219", "Outros bens não duradouros", "EXPENSE", null);
        createClassification("6261", "Comunicações", "EXPENSE", null);
        createClassification("6271", "Locação de edifícios", "EXPENSE", null);
        createClassification("6281", "Transporte Exterior", "EXPENSE", null);
        createClassification("6283", "Ajudas de custo Exterior", "EXPENSE", null);
        createClassification("6295", "Alimentação", "EXPENSE", null);

        // Despesas - Transferências
        createClassification("6312", "Serviços autónomos", "EXPENSE", null);
        createClassification("6422", "Associações desportivas", "EXPENSE", null);
        createClassification("6433", "Pensões provisórias de aposentação", "EXPENSE", null);
        createClassification("6434", "Pensões de aposentação, reforma, invalidade", "EXPENSE", null);
        createClassification("6499", "Outras transferências correntes", "EXPENSE", null);
        createClassification("6611", "Incentivos para a cobrança de receitas", "EXPENSE", null);
        createClassification("6691", "Outras despesas comuns", "EXPENSE", null);

        // Investimento e Dívida
        createClassification("2311", "Construções e grandes reparações", "EXPENSE", null);
        createClassification("2411", "Mobiliário e Material de secretaria", "EXPENSE", null);
        createClassification("2431", "Material de transporte", "EXPENSE", null);
        createClassification("2441", "Maquinaria e equipamentos", "EXPENSE", null);
        createClassification("1511", "Empréstimos para projetos (Multilateral)", "EXPENSE", null);
        createClassification("6511", "Juros e custos financeiros da dívida", "EXPENSE", null);

        // Universal Generic Backup
        createClassification("99.00.00", "Dotação Geral (Importado)", "EXPENSE", null);
    }

    private void createClassification(String code, String description, String type, String uemoaCode) {
        if (economicClassificationRepository.findByCode(code).isEmpty()) {
            economicClassificationRepository.save(EconomicClassification.builder()
                    .code(code)
                    .description(description)
                    .type(type)
                    .uemoaCode(uemoaCode)
                    .build());
        }
    }

    private FiscalYear ensureFiscalYear2025() {
        return fiscalYearRepository.findByYear(2025)
                .orElseGet(() -> fiscalYearRepository.save(FiscalYear.builder()
                        .year(2025)
                        .startDate(LocalDate.of(2025, 1, 1))
                        .endDate(LocalDate.of(2025, 12, 31))
                        .status("OPEN")
                        .build()));
    }

    private void seedItem(OgeItemDTO item, FiscalYear fiscalYear) {
        Ministry ministry;
        OrgUnit orgUnit;

        if ("ORG_UNIT".equals(item.getType()) && item.getMinistryCode() != null) {
            // Case 1: Subordinate Org Unit (Secretariats)
            // Find parent ministry
            ministry = ministryRepository.findByCode(item.getMinistryCode())
                    .orElseThrow(() -> new RuntimeException("Ministry not found for code: " + item.getMinistryCode()));

            // Find parent unit (Ministry Cabinet)
            OrgUnit parentUnit = orgUnitRepository.findByCode(item.getMinistryCode())
                    .orElseThrow(
                            () -> new RuntimeException("Parent Unit not found for code: " + item.getMinistryCode()));

            // Create Sub-Unit
            orgUnit = orgUnitRepository.findByCode(item.getCode())
                    .orElseGet(() -> orgUnitRepository.save(OrgUnit.builder()
                            .ministry(ministry)
                            .parentUnit(parentUnit)
                            .code(item.getCode())
                            .name(item.getName())
                            .unitType("Secretaria de Estado")
                            .isActive(true)
                            .build()));
        } else {
            // Case 2: Top Level Ministry
            ministry = ministryRepository.findByCode(item.getCode())
                    .orElseGet(() -> ministryRepository.save(Ministry.builder()
                            .code(item.getCode())
                            .name(item.getName())
                            .isActive(true)
                            .build()));

            // Create Main Org Unit (Cabinet)
            Ministry finalMinistry = ministry;
            orgUnit = orgUnitRepository.findByCode(item.getCode())
                    .orElseGet(() -> orgUnitRepository.save(OrgUnit.builder()
                            .ministry(finalMinistry)
                            .code(item.getCode())
                            .name(item.getName())
                            .unitType("Gabinete Ministerial")
                            .isActive(true)
                            .build()));
        }

        // C. Budget Line (Generic)
        String lineCode = item.getCode() + ".GEN";
        Ministry finalMinistryForLine = ministry;
        OrgUnit finalOrgUnitForLine = orgUnit;

        BudgetLine budgetLine = budgetLineRepository.findByCode(lineCode)
                .orElseGet(() -> budgetLineRepository.save(BudgetLine.builder()
                        .fiscalYear(fiscalYear)
                        .ministry(finalMinistryForLine.getId())
                        .orgUnit(finalOrgUnitForLine.getId())
                        .code(lineCode)
                        .description("Dotação Geral - " + item.getName())
                        .economicClass("99.00.00") // Generic
                        .build()));

        // D. Budget Entry (Initial Allocation)
        seedBudgetEntry(budgetLine, item.getTotalAllocated());
    }

    private void seedBudgetEntry(BudgetLine budgetLine, BigDecimal totalAllocated) {
        // Check if entry already exists to avoid duplication
        boolean entryExists = budgetEntryRepository.findAll().stream()
                .anyMatch(be -> be.getBudgetLine().getId().equals(budgetLine.getId())
                        && be.getType() == BudgetEntryType.INITIAL_ALLOCATION);

        if (!entryExists) {
            // Create Entry
            budgetEntryRepository.save(BudgetEntry.builder()
                    .budgetLine(budgetLine)
                    .type(BudgetEntryType.INITIAL_ALLOCATION)
                    .amount(totalAllocated.multiply(BigDecimal.valueOf(1000))) // Convert Mil FCFA to FCFA
                    .transactionDate(LocalDate.of(2025, 1, 1))
                    .documentReference("Lei OGE 2025")
                    .description("Dotação Inicial Importada")
                    .build());
        }
    }

    @Data
    static class OgeItemDTO {
        private String code;
        private String name;
        private BigDecimal totalAllocated;
        private String type; // MINISTRY, ORG_UNIT
        private String ministryCode; // Optional, for ORG_UNIT
    }

    @Data
    static class SalaryGridItemDTO {
        private String code;
        private String name;
        private String baseSalary;
        private String subsidy;
        private String gross;
    }
}
