from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from ..models import Orcamento as ModelOrcamento, ProdutoOrcamento as ModelProdutoOrcamento, ServicoOrcamento as ModelServicoOrcamento, MovimentacaoEstoque as ModelMovimentacaoEstoque
from ..schemas import Schemas
from . import Cliente, MovimentacaoEstoque
from datetime import datetime

def get_orcamentos(session: Session) -> list[Schemas.OrcamentoBase]:
    orcamentos = []
    clientes = Cliente.get_clientes(session)

    for orcamento in session.query(ModelOrcamento.Orcamento).all():
        for cliente in clientes:
            if cliente.id == orcamento.cliente_id:
                orcamento.cliente = cliente
                break
        orcamentos.append(orcamento)

    return orcamentos

def add_orcamento(orcamento: Schemas.OrcamentoBase, session: Session):
    novo_orcamento = ModelOrcamento.Orcamento(
        usuario_id=orcamento.usuario_id,
        cliente_id=orcamento.cliente_id,
        tipo=orcamento.tipo,
        situacao=orcamento.situacao,
        data_emissao=orcamento.data_emissao
    )
    session.add(novo_orcamento)
    session.commit()
    session.refresh(novo_orcamento)

    for produto_orcamento in orcamento.produtos:
        ligacao_produto_orcamento = ModelProdutoOrcamento.ProdutoOrcamento(
            orcamento_id=novo_orcamento.id,
            produto_id=produto_orcamento.produto_id,
            quantidade=produto_orcamento.quantidade,
            preco_unitario=produto_orcamento.preco_unitario
        )
        session.add(ligacao_produto_orcamento)
        session.commit()

        movimentacao = Schemas.MovimentacaoEstoqueCadastro(
            orcamento_id=novo_orcamento.id,
            produto_id=produto_orcamento.produto_id,
            quantidade=produto_orcamento.quantidade * -1,
            data=datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
            situacao=ModelMovimentacaoEstoque.SituacaoMovimentacaoEstoque.Solicitado
        )
        MovimentacaoEstoque.adicionar_movimentacao_de_estoque(movimentacao, session)

    for servico_orcamento in orcamento.servicos:
        ligacao_servico_orcamento = ModelServicoOrcamento.ServicoOrcamento(
            orcamento_id=novo_orcamento.id,
            servico_id=servico_orcamento.servico_id,
            tempo=servico_orcamento.tempo,
            preco_por_hora=servico_orcamento.preco_por_hora
        )
        session.add(ligacao_servico_orcamento)
        session.commit()

    return novo_orcamento

def aprovar_orcamento(id_orcamento: int, session: Session):
    orcamento = session.query(ModelOrcamento.Orcamento).filter_by(id=id_orcamento).first()
    if not orcamento:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Orçamento não encontrado!"
        )
    
    if orcamento.situacao != ModelOrcamento.SituacaoOrcamento.Pendente:
        raise HTTPException(
            status_code=status.HTTP_406_NOT_ACCEPTABLE,
            detail="Orçamento não está pendente para ser aprovado!"
        )
    
    orcamento.situacao = ModelOrcamento.SituacaoOrcamento.Aprovado
    session.add(orcamento)
    session.commit()
    session.refresh(orcamento)

    movimentacoes_estoque = orcamento.movimentacoes

    for movimentacao in movimentacoes_estoque:
        movimentacao = Schemas.MovimentacaoEstoqueAtualizacao(
            id = movimentacao.id,
            quantidade = movimentacao.quantidade,
            situacao = MovimentacaoEstoque.SituacaoMovimentacaoEstoque.Executado,
            data = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
        )
        MovimentacaoEstoque.update_movimentacao_de_estoque(movimentacao, session)

    return orcamento

def reprovar_orcamento(id_orcamento: int, session: Session):
    orcamento = session.query(ModelOrcamento.Orcamento).filter_by(id=id_orcamento).first()
    if not orcamento:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Orçamento não encontrado!"
        )
    
    if orcamento.situacao != ModelOrcamento.SituacaoOrcamento.Pendente:
        raise HTTPException(
            status_code=status.HTTP_406_NOT_ACCEPTABLE,
            detail="Orçamento não está pendente para ser aprovado!"
        )
    
    orcamento.situacao = ModelOrcamento.SituacaoOrcamento.Reprovado
    session.add(orcamento)
    session.commit()
    session.refresh(orcamento)

    movimentacoes_estoque = orcamento.movimentacoes

    for movimentacao in movimentacoes_estoque:
        movimentacao = Schemas.MovimentacaoEstoqueAtualizacao(
            id = movimentacao.id,
            quantidade = movimentacao.quantidade,
            situacao = MovimentacaoEstoque.SituacaoMovimentacaoEstoque.Cancelado,
            data = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
        )
        MovimentacaoEstoque.update_movimentacao_de_estoque(movimentacao, session)
    
    return orcamento

def atualizar_orcamento(id_orcamento: int, orcamento_atualizado: Schemas.OrcamentoBase, session: Session):
    orcamento_db = session.query(ModelOrcamento.Orcamento).filter_by(id=id_orcamento).first()

    if not orcamento_db:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Orçamento não encontrado!"
        )
    
    for produto_cadastrado in orcamento_db.produtos:
        session.delete(produto_cadastrado)

    for servico_cadastrado in orcamento_db.servicos:
        session.delete(servico_cadastrado)
    
    for produto_a_ser_cadastrado in orcamento_atualizado.produtos:
        session.add(ModelProdutoOrcamento.ProdutoOrcamento(
            orcamento_id=id_orcamento,
            produto_id=produto_a_ser_cadastrado.produto_id,
            quantidade=produto_a_ser_cadastrado.quantidade,
            preco_unitario=produto_a_ser_cadastrado.preco_unitario
        ))
    
    for servico_a_ser_cadastrado in orcamento_atualizado.servicos:
        session.add(ModelServicoOrcamento.ServicoOrcamento(
            orcamento_id=id_orcamento,
            servico_id=servico_a_ser_cadastrado.servico_id,
            tempo=servico_a_ser_cadastrado.tempo,
            preco_por_hora=servico_a_ser_cadastrado.preco_por_hora
        ))

    orcamento_data = orcamento_atualizado.dict(exclude_unset=True)
    for key, value in orcamento_data.items():
        if key != "produtos" and key != "servicos":
            setattr(orcamento_db, key, value)

    session.add(orcamento_db)
    session.commit()
    session.refresh(orcamento_db)

    return orcamento_db
