from datetime import datetime, timedelta
from functions.database import (
    Base, Militante, CotaMensal, TipoPagamento, Pagamento,
    MaterialVendido, TipoMaterial, VendaJornalAvulso, AssinaturaAnual,
    RelatorioCotasMensais, RelatorioVendasMateriais, engine, SessionLocal,
    Setor, ComiteCentral, Usuario, Role, EmailMilitante, Endereco,
    ComiteRegional, Celula, EstadoMilitante
)
import random
from faker import Faker
import time
from werkzeug.security import generate_password_hash

fake = Faker('pt_BR')

def criar_estrutura_organizacional(session):
    """Cria a estrutura organizacional básica"""
    print("\nCriando estrutura organizacional...")
    
    # Criar Comitê Central
    cc = ComiteCentral(nome="Comitê Central SP")
    session.add(cc)
    session.flush()
    
    # Criar Comitês Regionais
    crs = []
    for nome in ["CR São Paulo", "CR ABC", "CR Campinas"]:
        cr = ComiteRegional(nome=nome)
        session.add(cr)
        session.flush()
        crs.append(cr)
    
    # Criar Setores para cada CR
    setores = []
    for cr in crs:
        for i in range(2):  # 2 setores por CR
            setor = Setor(
                nome=f"Setor {i+1} - {cr.nome}",
                cr_id=cr.id
            )
            session.add(setor)
            session.flush()
            setores.append(setor)
    
    # Criar Células para cada Setor
    for setor in setores:
        for i in range(2):  # 2 células por setor
            celula = Celula(
                nome=f"Célula {i+1} - {setor.nome}",
                setor_id=setor.id
            )
            session.add(celula)
    
    session.commit()
    return crs, setores

def criar_tipos_pagamento(session):
    """Cria tipos de pagamento padrão"""
    print("\nCriando tipos de pagamento...")
    tipos = [
        "Dinheiro",
        "PIX",
        "Cartão de Crédito",
        "Cartão de Débito",
        "Transferência Bancária"
    ]
    for tipo in tipos:
        if not session.query(TipoPagamento).filter_by(descricao=tipo).first():
            session.add(TipoPagamento(descricao=tipo))
    session.commit()

def criar_tipos_material(session):
    """Cria tipos de material padrão"""
    print("\nCriando tipos de material...")
    tipos = [
        "Jornal",
        "Revista",
        "Livro",
        "Panfleto",
        "Cartilha"
    ]
    for tipo in tipos:
        if not session.query(TipoMaterial).filter_by(descricao=tipo).first():
            session.add(TipoMaterial(descricao=tipo))
    session.commit()

def criar_militantes(session, num_militantes, setores):
    """Cria militantes com todos os dados necessários"""
    print(f"\nCriando {num_militantes} militantes...")
    militantes = []
    emails_usados = set()
    
    for i in range(num_militantes):
        try:
            # Dados básicos
            nome = fake.name()
            cpf = fake.cpf()
            
            # Email único
            while True:
                email = fake.email()
                if email not in emails_usados:
                    emails_usados.add(email)
                    break
            
            # Criar endereço
            endereco = Endereco(
                cep=fake.postcode(),
                estado=fake.estado_sigla(),
                cidade=fake.city(),
                bairro=fake.bairro(),
                rua=fake.street_name(),
                numero=str(random.randint(1, 999)),
                complemento=f"Bloco {random.randint(1, 10)}, Apto {random.randint(1, 999)}" if random.random() < 0.3 else None
            )
            session.add(endereco)
            session.flush()
            
            # Selecionar setor e célula aleatórios
            setor = random.choice(setores)
            celula = random.choice(session.query(Celula).filter_by(setor_id=setor.id).all())
            
            # Definir responsabilidades
            responsabilidades = 0
            if random.random() < 0.2:  # 20% chance de ser Responsável de Finanças
                responsabilidades |= Militante.RESPONSAVEL_FINANCAS
            if random.random() < 0.2:  # 20% chance de ser Responsável de Imprensa
                responsabilidades |= Militante.RESPONSAVEL_IMPRENSA
            if random.random() < 0.2:  # 20% chance de ser Quadro-Orientador
                responsabilidades |= Militante.QUADRO_ORIENTADOR
            if random.random() < 0.2:  # 20% chance de ser Secretário
                responsabilidades |= Militante.SECRETARIO
            if random.random() < 0.2:  # 20% chance de ser MPS
                responsabilidades |= Militante.MPS
            if random.random() < 0.2:  # 20% chance de ser Tesoureiro
                responsabilidades |= Militante.TESOUREIRO
            if random.random() < 0.2:  # 20% chance de ser MNS
                responsabilidades |= Militante.MNS
            if random.random() < 0.2:  # 20% chance de ser da Juventude
                responsabilidades |= Militante.JUVENTUDE
            if random.random() < 0.3:  # 30% chance de ser Aspirante
                responsabilidades |= Militante.ASPIRANTE
            
            print(f"Criando militante {i+1}: {nome}")
            
            # Criar militante com todos os dados
            militante = Militante(
                nome=nome,
                cpf=cpf,
                titulo_eleitoral=str(random.randint(100000000000, 999999999999)),
                data_nascimento=fake.date_of_birth(minimum_age=18, maximum_age=65),
                data_entrada_oci=fake.date_between(start_date='-5y', end_date='today'),
                data_efetivacao_oci=fake.date_between(start_date='-4y', end_date='today'),
                telefone1=fake.phone_number(),
                telefone2=fake.phone_number() if random.random() < 0.3 else None,
                profissao=fake.job(),
                regime_trabalho=random.choice(['CLT', 'PJ', 'Estatutário', 'Autônomo']),
                empresa=fake.company(),
                contratante=fake.company() if random.random() < 0.2 else None,
                instituicao_ensino=fake.company() if random.random() < 0.4 else None,
                tipo_instituicao=random.choice(['Federal', 'Estadual', 'Municipal', 'Privada']) if random.random() < 0.4 else None,
                sindicato=fake.company() if random.random() < 0.6 else None,
                cargo_sindical=random.choice(['Diretor', 'Delegado', 'Conselheiro']) if random.random() < 0.3 else None,
                dirigente_sindical=random.random() < 0.2,
                central_sindical=random.choice(['CUT', 'CSP-Conlutas', 'CTB', 'Força Sindical']) if random.random() < 0.4 else None,
                endereco_id=endereco.id,
                celula_id=celula.id,
                responsabilidades=responsabilidades,
                estado=random.choice(list(EstadoMilitante))
            )
            session.add(militante)
            session.flush()
            
            # Criar email do militante
            email_militante = EmailMilitante(
                militante_id=militante.id,
                endereco_email=email
            )
            session.add(email_militante)
            
            militantes.append(militante)
            session.commit()
            
        except Exception as e:
            print(f"Erro ao criar militante {i+1}: {e}")
            session.rollback()
            continue
    
    return militantes

def criar_cotas(session, militantes):
    """Cria cotas mensais para os militantes"""
    print("\nCriando cotas mensais...")
    for militante in militantes:
        try:
            # Criar 12 cotas (1 ano) para cada militante
            for i in range(12):
                data_base = datetime.now() - timedelta(days=30 * i)
                valor = random.uniform(50, 200)
                cota = CotaMensal(
                    militante_id=militante.id,
                    valor_antigo=valor,
                    valor_novo=valor * 1.1,
                    data_alteracao=data_base,
                    data_vencimento=data_base + timedelta(days=30),
                    pago=random.choice([True, False])
                )
                session.add(cota)
            session.commit()
        except Exception as e:
            print(f"Erro ao criar cotas para militante {militante.nome}: {e}")
            session.rollback()

def criar_pagamentos(session, militantes):
    """Cria pagamentos para os militantes"""
    print("\nCriando pagamentos...")
    tipos_pagamento = session.query(TipoPagamento).all()
    
    for militante in militantes:
        try:
            # Criar entre 3 e 8 pagamentos por militante
            for _ in range(random.randint(3, 8)):
                tipo = random.choice(tipos_pagamento)
                pagamento = Pagamento(
                    militante_id=militante.id,
                    tipo_pagamento=tipo.descricao,  # Usando a descrição do tipo
                    valor=random.uniform(50, 500),
                    data_pagamento=fake.date_between(start_date='-1y', end_date='today')
                )
                session.add(pagamento)
            session.commit()
        except Exception as e:
            print(f"Erro ao criar pagamentos para militante {militante.nome}: {e}")
            session.rollback()

def criar_materiais_vendidos(session, militantes):
    """Cria registros de materiais vendidos"""
    print("\nCriando materiais vendidos...")
    tipos_material = session.query(TipoMaterial).all()
    
    for militante in militantes:
        try:
            # Criar entre 2 e 5 materiais vendidos por militante
            for _ in range(random.randint(2, 5)):
                material = MaterialVendido(
                    militante_id=militante.id,
                    tipo_material_id=random.choice(tipos_material).id,
                    descricao=fake.sentence(),
                    valor=random.uniform(20, 100),
                    data_venda=fake.date_time_between(start_date='-1y', end_date='now')
                )
                session.add(material)
            session.commit()
        except Exception as e:
            print(f"Erro ao criar materiais vendidos para militante {militante.nome}: {e}")
            session.rollback()

def criar_vendas_jornal(session, militantes):
    """Cria vendas de jornal avulso"""
    print("\nCriando vendas de jornal...")
    for militante in militantes:
        try:
            # Criar entre 2 e 6 vendas de jornal por militante
            for _ in range(random.randint(2, 6)):
                quantidade = random.randint(1, 10)
                valor_unitario = random.uniform(5, 15)
                venda = VendaJornalAvulso(
                    militante_id=militante.id,
                    quantidade=quantidade,
                    valor_total=quantidade * valor_unitario,
                    data_venda=fake.date_time_between(start_date='-1y', end_date='now')
                )
                session.add(venda)
            session.commit()
        except Exception as e:
            print(f"Erro ao criar vendas de jornal para militante {militante.nome}: {e}")
            session.rollback()

def criar_assinaturas(session, militantes):
    """Cria assinaturas anuais"""
    print("\nCriando assinaturas anuais...")
    tipos_material = session.query(TipoMaterial).all()
    
    for militante in militantes:
        try:
            # 30% de chance de ter assinatura
            if random.random() < 0.3:
                data_inicio = fake.date_time_between(start_date='-1y', end_date='now')
                assinatura = AssinaturaAnual(
                    militante_id=militante.id,
                    tipo_material_id=random.choice(tipos_material).id,
                    quantidade=random.randint(1, 3),
                    valor_total=random.uniform(100, 500),
                    data_inicio=data_inicio,
                    data_fim=data_inicio + timedelta(days=365)
                )
                session.add(assinatura)
            session.commit()
        except Exception as e:
            print(f"Erro ao criar assinatura para militante {militante.nome}: {e}")
            session.rollback()

def seed_database():
    """Função principal para popular o banco de dados"""
    session = SessionLocal()
    try:
        print("Iniciando população do banco de dados...")
        
        # Criar estrutura organizacional
        crs, setores = criar_estrutura_organizacional(session)
        
        # Criar tipos básicos
        criar_tipos_pagamento(session)
        criar_tipos_material(session)
        
        # Criar militantes (30 militantes para teste)
        militantes = criar_militantes(session, 30, setores)
        
        # Criar dados financeiros e materiais
        criar_cotas(session, militantes)
        criar_pagamentos(session, militantes)
        criar_materiais_vendidos(session, militantes)
        criar_vendas_jornal(session, militantes)
        criar_assinaturas(session, militantes)
        
        print("\nBanco de dados populado com sucesso!")
        
    except Exception as e:
        print(f"Erro durante a população do banco: {e}")
        session.rollback()
    finally:
        session.close()

if __name__ == "__main__":
    seed_database() 