from functions.database import get_db_connection, Pagamento, Militante, TipoPagamento
from sqlalchemy.orm import joinedload
from datetime import datetime
from typing import List, Dict, Optional

class PagamentoModel:
    """Model para operações com pagamentos"""
    
    @staticmethod
    def criar_pagamento(data: Dict) -> Dict:
        """Cria um novo pagamento"""
        db = get_db_connection()
        try:
            pagamento = Pagamento(
                militante_id=data['militante_id'],
                tipo_pagamento_id=data.get('tipo_pagamento_id'),
                valor=data['valor'],
                data_pagamento=data['data_pagamento']
            )
            db.add(pagamento)
            db.commit()
            
            return {
                'status': 'success',
                'message': 'Pagamento criado com sucesso',
                'pagamento_id': pagamento.id
            }
            
        except Exception as e:
            db.rollback()
            return {
                'status': 'error',
                'message': f'Erro ao criar pagamento: {str(e)}'
            }
        finally:
            db.close()
    
    @staticmethod
    def listar_pagamentos() -> List[Pagamento]:
        """Lista todos os pagamentos"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).join(Militante).order_by(Pagamento.data_pagamento.desc()).all()
        finally:
            db.close()
    
    @staticmethod
    def buscar_por_id(pagamento_id: int) -> Optional[Pagamento]:
        """Busca um pagamento por ID"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).get(pagamento_id)
        finally:
            db.close()
    
    @staticmethod
    def atualizar_pagamento(pagamento_id: int, data: Dict) -> Dict:
        """Atualiza um pagamento existente"""
        db = get_db_connection()
        try:
            pagamento = db.query(Pagamento).get(pagamento_id)
            
            if not pagamento:
                return {
                    'status': 'error',
                    'message': 'Pagamento não encontrado'
                }
            
            pagamento.militante_id = data.get('militante_id', pagamento.militante_id)
            pagamento.tipo_pagamento_id = data.get('tipo_pagamento_id', pagamento.tipo_pagamento_id)
            pagamento.valor = data.get('valor', pagamento.valor)
            pagamento.data_pagamento = data.get('data_pagamento', pagamento.data_pagamento)
            
            db.commit()
            
            return {
                'status': 'success',
                'message': 'Pagamento atualizado com sucesso'
            }
            
        except Exception as e:
            db.rollback()
            return {
                'status': 'error',
                'message': f'Erro ao atualizar pagamento: {str(e)}'
            }
        finally:
            db.close()
    
    @staticmethod
    def excluir_pagamento(pagamento_id: int) -> Dict:
        """Exclui um pagamento"""
        db = get_db_connection()
        try:
            pagamento = db.query(Pagamento).get(pagamento_id)
            if not pagamento:
                return {
                    'status': 'error',
                    'message': 'Pagamento não encontrado'
                }
            
            db.delete(pagamento)
            db.commit()
            
            return {
                'status': 'success',
                'message': 'Pagamento excluído com sucesso'
            }
            
        except Exception as e:
            db.rollback()
            return {
                'status': 'error',
                'message': f'Erro ao excluir pagamento: {str(e)}'
            }
        finally:
            db.close()
    
    @staticmethod
    def listar_por_celula(celula_id: int) -> List[Pagamento]:
        """Lista pagamentos de uma célula específica"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).filter_by(celula_id=celula_id).all()
        finally:
            db.close()
    
    @staticmethod
    def listar_por_setor(setor_id: int) -> List[Pagamento]:
        """Lista pagamentos de um setor específico"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).join(Usuario).filter(Usuario.setor_id == setor_id).all()
        finally:
            db.close()
    
    @staticmethod
    def listar_por_cr(cr_id: int) -> List[Pagamento]:
        """Lista pagamentos de um CR específico"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).join(Usuario).filter(Usuario.cr_id == cr_id).all()
        finally:
            db.close()
    
    @staticmethod
    def listar_por_militante(militante_id: int) -> List[Pagamento]:
        """Lista pagamentos de um militante específico"""
        db = get_db_connection()
        try:
            return db.query(Pagamento).filter_by(militante_id=militante_id).order_by(Pagamento.data_pagamento.desc()).all()
        finally:
            db.close()
    
    @staticmethod
    def obter_tipos_pagamento() -> List[TipoPagamento]:
        """Obtém todos os tipos de pagamento"""
        db = get_db_connection()
        try:
            return db.query(TipoPagamento).order_by(TipoPagamento.descricao).all()
        finally:
            db.close()
    
    @staticmethod
    def obter_militantes() -> List[Militante]:
        """Obtém todos os militantes"""
        db = get_db_connection()
        try:
            return db.query(Militante).order_by(Militante.nome).all()
        finally:
            db.close()
    
    @staticmethod
    def formatar_dados_pagamento(pagamento: Pagamento) -> Dict:
        """Formata os dados de um pagamento para retorno JSON"""
        return {
            'id': pagamento.id,
            'militante_id': pagamento.militante_id,
            'tipo_pagamento_id': pagamento.tipo_pagamento_id,
            'valor': float(pagamento.valor) if pagamento.valor else 0.0,
            'data_pagamento': pagamento.data_pagamento.strftime('%Y-%m-%d') if pagamento.data_pagamento else None,
            'militante_nome': pagamento.militante.nome if pagamento.militante else None,
            'tipo_pagamento_nome': pagamento.tipo_pagamento.descricao if pagamento.tipo_pagamento else None
        } 