"""
Arcádia People - Motor de RH (HRM)
Serviço FastAPI para gestão de recursos humanos
"""

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
from datetime import datetime, date
from decimal import Decimal
import json
import os

app = FastAPI(
    title="Arcádia People",
    description="Motor de RH - Folha de Pagamento, Ponto, Férias, eSocial",
    version="1.0.0"
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=[os.getenv("APP_URL", "http://localhost:5000")],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ========== Tabelas de Cálculo (2024) ==========

TABELA_INSS_2024 = [
    {"faixaInicio": 0, "faixaFim": 1412.00, "aliquota": 7.5},
    {"faixaInicio": 1412.01, "faixaFim": 2666.68, "aliquota": 9.0},
    {"faixaInicio": 2666.69, "faixaFim": 4000.03, "aliquota": 12.0},
    {"faixaInicio": 4000.04, "faixaFim": 7786.02, "aliquota": 14.0},
]

TETO_INSS_2024 = 7786.02
DEDUCAO_DEPENDENTE_IRRF = 189.59

TABELA_IRRF_2024 = [
    {"faixaInicio": 0, "faixaFim": 2259.20, "aliquota": 0, "deducao": 0},
    {"faixaInicio": 2259.21, "faixaFim": 2826.65, "aliquota": 7.5, "deducao": 169.44},
    {"faixaInicio": 2826.66, "faixaFim": 3751.05, "aliquota": 15.0, "deducao": 381.44},
    {"faixaInicio": 3751.06, "faixaFim": 4664.68, "aliquota": 22.5, "deducao": 662.77},
    {"faixaInicio": 4664.69, "faixaFim": 999999999, "aliquota": 27.5, "deducao": 896.00},
]

SALARIO_FAMILIA_2024 = [
    {"faixaFim": 1819.26, "valor": 62.04},
]

# ========== Models ==========

class Funcionario(BaseModel):
    nome: str
    cpf: str
    salario: float
    dataAdmissao: str
    cargoId: Optional[int] = None
    departamentoId: Optional[int] = None
    tipoContrato: str = "clt"
    jornadaTrabalho: str = "44h"

class CalculoFolhaRequest(BaseModel):
    funcionarioId: int
    competencia: str  # YYYY-MM
    salarioBase: float
    diasTrabalhados: int = 30
    horasExtras50: float = 0
    horasExtras100: float = 0
    horasNoturnas: float = 0
    faltas: int = 0
    atrasos: float = 0
    dependentesIrrf: int = 0
    descontosAdicionais: List[Dict[str, Any]] = []
    proventosAdicionais: List[Dict[str, Any]] = []

class CalculoFeriasRequest(BaseModel):
    funcionarioId: int
    salarioBase: float
    diasFerias: int = 30
    diasAbono: int = 0
    mediaHorasExtras: float = 0
    dependentesIrrf: int = 0

class CalculoRescisaoRequest(BaseModel):
    funcionarioId: int
    salarioBase: float
    dataAdmissao: str
    dataDemissao: str
    tipoRescisao: str  # sem_justa_causa, justa_causa, pedido_demissao
    saldoFerias: int = 0
    avisoPrevio: str = "trabalhado"  # trabalhado, indenizado, dispensado
    dependentesIrrf: int = 0

class PontoRequest(BaseModel):
    funcionarioId: int
    data: str
    entrada1: str
    saida1: str
    entrada2: Optional[str] = None
    saida2: Optional[str] = None
    jornadaDiaria: float = 8.0

# ========== Funções de Cálculo ==========

def calcular_inss(salario_bruto: float) -> dict:
    """
    Calcula INSS progressivo (2024) conforme Portaria MPS
    
    Tabela INSS 2024:
    Faixa 1: Até R$ 1.412,00 = 7,5%
    Faixa 2: De R$ 1.412,01 a R$ 2.666,68 = 9%
    Faixa 3: De R$ 2.666,69 a R$ 4.000,03 = 12%
    Faixa 4: De R$ 4.000,04 a R$ 7.786,02 = 14%
    
    Cálculo progressivo: cada faixa incide apenas sobre o valor dentro dela.
    """
    if salario_bruto > TETO_INSS_2024:
        base_calculo = TETO_INSS_2024
    else:
        base_calculo = salario_bruto
    
    inss_total = 0.0
    detalhamento = []
    
    # Limites exatos das faixas para cálculo progressivo
    faixas = [
        {"limite_inferior": 0, "limite_superior": 1412.00, "aliquota": 7.5},
        {"limite_inferior": 1412.00, "limite_superior": 2666.68, "aliquota": 9.0},
        {"limite_inferior": 2666.68, "limite_superior": 4000.03, "aliquota": 12.0},
        {"limite_inferior": 4000.03, "limite_superior": 7786.02, "aliquota": 14.0},
    ]
    
    for i, faixa in enumerate(faixas):
        limite_inferior = faixa["limite_inferior"]
        limite_superior = faixa["limite_superior"]
        aliquota = faixa["aliquota"]
        
        if base_calculo <= limite_inferior:
            break
        
        # Base da faixa: min(salário, limite_superior) - limite_inferior
        teto_faixa = min(base_calculo, limite_superior)
        base_faixa = teto_faixa - limite_inferior
        
        if base_faixa > 0:
            valor_faixa = base_faixa * (aliquota / 100)
            inss_total += valor_faixa
            detalhamento.append({
                "faixa": i + 1,
                "limiteInferior": limite_inferior,
                "limiteSuperior": limite_superior,
                "base": round(base_faixa, 2),
                "aliquota": aliquota,
                "valor": round(valor_faixa, 2)
            })
    
    return {
        "baseCalculo": round(base_calculo, 2),
        "valorInss": round(inss_total, 2),
        "tetoAplicado": salario_bruto > TETO_INSS_2024,
        "detalhamento": detalhamento
    }

def calcular_irrf(base_irrf: float, dependentes: int = 0) -> dict:
    """Calcula IRRF (2024)"""
    deducao_dependentes = dependentes * DEDUCAO_DEPENDENTE_IRRF
    base_calculo = base_irrf - deducao_dependentes
    
    if base_calculo < 0:
        base_calculo = 0
    
    irrf = 0
    aliquota_efetiva = 0
    faixa_aplicada = 0
    
    for i, faixa in enumerate(TABELA_IRRF_2024):
        if base_calculo >= faixa["faixaInicio"] and base_calculo <= faixa["faixaFim"]:
            irrf = (base_calculo * faixa["aliquota"] / 100) - faixa["deducao"]
            aliquota_efetiva = faixa["aliquota"]
            faixa_aplicada = i + 1
            break
    
    if irrf < 0:
        irrf = 0
    
    return {
        "baseCalculo": round(base_calculo, 2),
        "deducaoDependentes": round(deducao_dependentes, 2),
        "aliquotaEfetiva": aliquota_efetiva,
        "faixaAplicada": faixa_aplicada,
        "valorIrrf": round(irrf, 2)
    }

def calcular_fgts(base_fgts: float) -> dict:
    """Calcula FGTS (8%)"""
    valor_fgts = base_fgts * 0.08
    return {
        "baseCalculo": round(base_fgts, 2),
        "aliquota": 8.0,
        "valorFgts": round(valor_fgts, 2)
    }

def calcular_salario_familia(salario: float, filhos_menores: int) -> dict:
    """Calcula Salário Família"""
    valor_cota = 0
    for faixa in SALARIO_FAMILIA_2024:
        if salario <= faixa["faixaFim"]:
            valor_cota = faixa["valor"]
            break
    
    valor_total = valor_cota * filhos_menores
    
    return {
        "salarioBase": round(salario, 2),
        "filhosMenores": filhos_menores,
        "valorCota": valor_cota,
        "valorTotal": round(valor_total, 2),
        "temDireito": valor_cota > 0
    }

def calcular_horas_trabalhadas(entrada1: str, saida1: str, entrada2: str = None, saida2: str = None) -> dict:
    """Calcula horas trabalhadas a partir dos registros de ponto"""
    def time_to_minutes(time_str: str) -> int:
        h, m = map(int, time_str.split(":"))
        return h * 60 + m
    
    minutos_periodo1 = time_to_minutes(saida1) - time_to_minutes(entrada1)
    minutos_periodo2 = 0
    
    if entrada2 and saida2:
        minutos_periodo2 = time_to_minutes(saida2) - time_to_minutes(entrada2)
    
    total_minutos = minutos_periodo1 + minutos_periodo2
    total_horas = total_minutos / 60
    
    return {
        "periodo1": round(minutos_periodo1 / 60, 2),
        "periodo2": round(minutos_periodo2 / 60, 2),
        "totalHoras": round(total_horas, 2),
        "totalMinutos": total_minutos
    }

# ========== Endpoints ==========

@app.get("/")
async def root():
    return {
        "service": "Arcádia People",
        "version": "1.0.0",
        "status": "running",
        "modules": ["funcionarios", "folha", "ferias", "ponto", "beneficios", "esocial"]
    }

@app.get("/health")
async def health():
    return {"status": "healthy", "timestamp": datetime.now().isoformat()}

@app.get("/tabelas/inss")
async def get_tabela_inss():
    """Retorna tabela INSS atual"""
    return {
        "vigencia": "2024",
        "teto": TETO_INSS_2024,
        "faixas": TABELA_INSS_2024
    }

@app.get("/tabelas/irrf")
async def get_tabela_irrf():
    """Retorna tabela IRRF atual"""
    return {
        "vigencia": "2024",
        "deducaoDependente": DEDUCAO_DEPENDENTE_IRRF,
        "faixas": TABELA_IRRF_2024
    }

@app.get("/tabelas/salario-familia")
async def get_tabela_salario_familia():
    """Retorna tabela Salário Família atual"""
    return {
        "vigencia": "2024",
        "faixas": SALARIO_FAMILIA_2024
    }

@app.post("/calcular/inss")
async def calcular_inss_endpoint(salario: float):
    """Calcula INSS para um salário"""
    return calcular_inss(salario)

@app.post("/calcular/irrf")
async def calcular_irrf_endpoint(base: float, dependentes: int = 0):
    """Calcula IRRF para uma base"""
    return calcular_irrf(base, dependentes)

@app.post("/calcular/folha")
async def calcular_folha(request: CalculoFolhaRequest):
    """Calcula folha de pagamento completa para um funcionário"""
    
    # Cálculo do salário proporcional
    salario_proporcional = request.salarioBase * (request.diasTrabalhados / 30)
    
    # Desconto de faltas
    valor_dia = request.salarioBase / 30
    desconto_faltas = valor_dia * request.faltas
    
    # Horas extras
    valor_hora = request.salarioBase / 220  # 220 horas mensais padrão
    valor_he_50 = request.horasExtras50 * (valor_hora * 1.5)
    valor_he_100 = request.horasExtras100 * (valor_hora * 2.0)
    
    # Adicional noturno (20%)
    valor_adicional_noturno = request.horasNoturnas * (valor_hora * 0.2)
    
    # Total de proventos
    proventos_adicionais = sum(p.get("valor", 0) for p in request.proventosAdicionais)
    total_proventos = (
        salario_proporcional + 
        valor_he_50 + 
        valor_he_100 + 
        valor_adicional_noturno +
        proventos_adicionais
    )
    
    # INSS
    inss_calc = calcular_inss(total_proventos)
    valor_inss = inss_calc["valorInss"]
    
    # IRRF (base = bruto - INSS)
    base_irrf = total_proventos - valor_inss
    irrf_calc = calcular_irrf(base_irrf, request.dependentesIrrf)
    valor_irrf = irrf_calc["valorIrrf"]
    
    # FGTS
    fgts_calc = calcular_fgts(total_proventos)
    valor_fgts = fgts_calc["valorFgts"]
    
    # Descontos adicionais
    descontos_adicionais = sum(d.get("valor", 0) for d in request.descontosAdicionais)
    
    # Total de descontos
    total_descontos = valor_inss + valor_irrf + desconto_faltas + descontos_adicionais
    
    # Líquido
    total_liquido = total_proventos - total_descontos
    
    return {
        "funcionarioId": request.funcionarioId,
        "competencia": request.competencia,
        "proventos": {
            "salarioBase": round(request.salarioBase, 2),
            "salarioProporcional": round(salario_proporcional, 2),
            "horasExtras50": {
                "horas": request.horasExtras50,
                "valor": round(valor_he_50, 2)
            },
            "horasExtras100": {
                "horas": request.horasExtras100,
                "valor": round(valor_he_100, 2)
            },
            "adicionalNoturno": {
                "horas": request.horasNoturnas,
                "valor": round(valor_adicional_noturno, 2)
            },
            "adicionais": request.proventosAdicionais,
            "total": round(total_proventos, 2)
        },
        "descontos": {
            "inss": inss_calc,
            "irrf": irrf_calc,
            "faltas": {
                "dias": request.faltas,
                "valor": round(desconto_faltas, 2)
            },
            "adicionais": request.descontosAdicionais,
            "total": round(total_descontos, 2)
        },
        "encargos": {
            "fgts": fgts_calc,
            "inssPatronal": {
                "aliquota": 20.0,
                "valor": round(total_proventos * 0.20, 2)
            }
        },
        "resumo": {
            "totalProventos": round(total_proventos, 2),
            "totalDescontos": round(total_descontos, 2),
            "totalLiquido": round(total_liquido, 2),
            "custoEmpresa": round(total_proventos + valor_fgts + (total_proventos * 0.20), 2)
        }
    }

@app.post("/calcular/ferias")
async def calcular_ferias(request: CalculoFeriasRequest):
    """Calcula férias"""
    
    # Valor base das férias
    valor_ferias = request.salarioBase * (request.diasFerias / 30)
    
    # Adicional de 1/3
    terco_constitucional = valor_ferias / 3
    
    # Abono pecuniário (venda de dias)
    valor_abono = 0
    terco_abono = 0
    if request.diasAbono > 0:
        valor_abono = request.salarioBase * (request.diasAbono / 30)
        terco_abono = valor_abono / 3
    
    # Média de horas extras
    media_he = request.mediaHorasExtras
    
    # Total bruto
    total_bruto = valor_ferias + terco_constitucional + valor_abono + terco_abono + media_he
    
    # INSS sobre férias
    inss_calc = calcular_inss(total_bruto)
    valor_inss = inss_calc["valorInss"]
    
    # IRRF
    base_irrf = total_bruto - valor_inss
    irrf_calc = calcular_irrf(base_irrf, request.dependentesIrrf)
    valor_irrf = irrf_calc["valorIrrf"]
    
    # Líquido
    total_liquido = total_bruto - valor_inss - valor_irrf
    
    return {
        "funcionarioId": request.funcionarioId,
        "diasFerias": request.diasFerias,
        "diasAbono": request.diasAbono,
        "proventos": {
            "ferias": round(valor_ferias, 2),
            "tercoConstitucional": round(terco_constitucional, 2),
            "abonoPecuniario": round(valor_abono, 2),
            "tercoAbono": round(terco_abono, 2),
            "mediaHorasExtras": round(media_he, 2),
            "total": round(total_bruto, 2)
        },
        "descontos": {
            "inss": inss_calc,
            "irrf": irrf_calc,
            "total": round(valor_inss + valor_irrf, 2)
        },
        "resumo": {
            "totalBruto": round(total_bruto, 2),
            "totalDescontos": round(valor_inss + valor_irrf, 2),
            "totalLiquido": round(total_liquido, 2)
        }
    }

@app.post("/calcular/rescisao")
async def calcular_rescisao(request: CalculoRescisaoRequest):
    """Calcula rescisão de contrato de trabalho"""
    from datetime import datetime
    
    data_admissao = datetime.strptime(request.dataAdmissao, "%Y-%m-%d")
    data_demissao = datetime.strptime(request.dataDemissao, "%Y-%m-%d")
    
    # Tempo de serviço
    dias_trabalhados = (data_demissao - data_admissao).days
    meses_trabalhados = dias_trabalhados / 30
    anos_trabalhados = dias_trabalhados / 365
    
    # Saldo de salário (dias do mês da demissão)
    dia_demissao = data_demissao.day
    saldo_salario = request.salarioBase * (dia_demissao / 30)
    
    # 13º proporcional
    meses_13 = data_demissao.month
    decimo_terceiro = (request.salarioBase / 12) * meses_13
    
    # Férias proporcionais + 1/3
    meses_ferias = int(meses_trabalhados % 12)
    if meses_ferias == 0:
        meses_ferias = int(meses_trabalhados)
    ferias_proporcionais = (request.salarioBase / 12) * meses_ferias
    terco_ferias = ferias_proporcionais / 3
    
    # Férias vencidas
    ferias_vencidas = request.salarioBase * (request.saldoFerias / 30)
    terco_vencidas = ferias_vencidas / 3
    
    # Aviso prévio
    aviso_previo = 0
    dias_aviso = 30 + (3 * int(anos_trabalhados))
    if dias_aviso > 90:
        dias_aviso = 90
        
    if request.tipoRescisao == "sem_justa_causa" and request.avisoPrevio == "indenizado":
        aviso_previo = request.salarioBase * (dias_aviso / 30)
    
    # Multa FGTS (40% ou 20%)
    # Estimativa do saldo FGTS (8% do salário * meses)
    saldo_fgts_estimado = (request.salarioBase * 0.08) * meses_trabalhados
    multa_fgts = 0
    
    if request.tipoRescisao == "sem_justa_causa":
        multa_fgts = saldo_fgts_estimado * 0.40
    elif request.tipoRescisao == "acordo":
        multa_fgts = saldo_fgts_estimado * 0.20
    
    # Total bruto
    total_bruto = (
        saldo_salario +
        decimo_terceiro +
        ferias_proporcionais +
        terco_ferias +
        ferias_vencidas +
        terco_vencidas +
        aviso_previo
    )
    
    # Descontos
    inss_calc = calcular_inss(saldo_salario)
    irrf_calc = calcular_irrf(total_bruto - inss_calc["valorInss"], request.dependentesIrrf)
    
    total_descontos = inss_calc["valorInss"] + irrf_calc["valorIrrf"]
    total_liquido = total_bruto - total_descontos + multa_fgts
    
    return {
        "funcionarioId": request.funcionarioId,
        "tipoRescisao": request.tipoRescisao,
        "tempoServico": {
            "dias": dias_trabalhados,
            "meses": round(meses_trabalhados, 1),
            "anos": round(anos_trabalhados, 1)
        },
        "verbas": {
            "saldoSalario": round(saldo_salario, 2),
            "decimoTerceiro": round(decimo_terceiro, 2),
            "feriasProporcionais": round(ferias_proporcionais, 2),
            "tercoFerias": round(terco_ferias, 2),
            "feriasVencidas": round(ferias_vencidas, 2),
            "tercoVencidas": round(terco_vencidas, 2),
            "avisoPrevio": {
                "tipo": request.avisoPrevio,
                "dias": dias_aviso,
                "valor": round(aviso_previo, 2)
            },
            "totalBruto": round(total_bruto, 2)
        },
        "descontos": {
            "inss": inss_calc,
            "irrf": irrf_calc,
            "total": round(total_descontos, 2)
        },
        "fgts": {
            "saldoEstimado": round(saldo_fgts_estimado, 2),
            "multa": round(multa_fgts, 2),
            "percentualMulta": 40 if request.tipoRescisao == "sem_justa_causa" else 20 if request.tipoRescisao == "acordo" else 0
        },
        "resumo": {
            "totalBruto": round(total_bruto, 2),
            "totalDescontos": round(total_descontos, 2),
            "multaFgts": round(multa_fgts, 2),
            "totalLiquido": round(total_liquido, 2)
        }
    }

@app.post("/calcular/ponto")
async def calcular_ponto(request: PontoRequest):
    """Calcula horas trabalhadas e extras"""
    
    horas = calcular_horas_trabalhadas(
        request.entrada1,
        request.saida1,
        request.entrada2,
        request.saida2
    )
    
    jornada_diaria = request.jornadaDiaria
    horas_trabalhadas = horas["totalHoras"]
    
    horas_extras = max(0, horas_trabalhadas - jornada_diaria)
    horas_faltantes = max(0, jornada_diaria - horas_trabalhadas)
    
    # Verificar adicional noturno (22h às 5h)
    horas_noturnas = 0  # Simplificado - precisaria de lógica mais complexa
    
    return {
        "funcionarioId": request.funcionarioId,
        "data": request.data,
        "registros": {
            "entrada1": request.entrada1,
            "saida1": request.saida1,
            "entrada2": request.entrada2,
            "saida2": request.saida2
        },
        "calculo": {
            "jornadaDiaria": jornada_diaria,
            "horasTrabalhadas": round(horas_trabalhadas, 2),
            "horasExtras": round(horas_extras, 2),
            "horasFaltantes": round(horas_faltantes, 2),
            "horasNoturnas": round(horas_noturnas, 2)
        },
        "detalhamento": horas
    }

@app.get("/esocial/eventos")
async def get_eventos_esocial():
    """Lista eventos do eSocial suportados"""
    eventos = [
        {"codigo": "S-1000", "descricao": "Informações do Empregador", "tipo": "tabela"},
        {"codigo": "S-1005", "descricao": "Tabela de Estabelecimentos", "tipo": "tabela"},
        {"codigo": "S-1010", "descricao": "Tabela de Rubricas", "tipo": "tabela"},
        {"codigo": "S-1020", "descricao": "Tabela de Lotações Tributárias", "tipo": "tabela"},
        {"codigo": "S-1030", "descricao": "Tabela de Cargos/Empregos Públicos", "tipo": "tabela"},
        {"codigo": "S-1040", "descricao": "Tabela de Funções/Cargos em Comissão", "tipo": "tabela"},
        {"codigo": "S-1050", "descricao": "Tabela de Horários/Turnos de Trabalho", "tipo": "tabela"},
        {"codigo": "S-1070", "descricao": "Tabela de Processos Administrativos/Judiciais", "tipo": "tabela"},
        {"codigo": "S-2190", "descricao": "Registro Preliminar de Trabalhador", "tipo": "nao_periodico"},
        {"codigo": "S-2200", "descricao": "Cadastramento Inicial / Admissão", "tipo": "nao_periodico"},
        {"codigo": "S-2205", "descricao": "Alteração de Dados Cadastrais", "tipo": "nao_periodico"},
        {"codigo": "S-2206", "descricao": "Alteração de Contrato de Trabalho", "tipo": "nao_periodico"},
        {"codigo": "S-2230", "descricao": "Afastamento Temporário", "tipo": "nao_periodico"},
        {"codigo": "S-2299", "descricao": "Desligamento", "tipo": "nao_periodico"},
        {"codigo": "S-2300", "descricao": "Trabalhador Sem Vínculo - Início", "tipo": "nao_periodico"},
        {"codigo": "S-2306", "descricao": "Trabalhador Sem Vínculo - Alteração", "tipo": "nao_periodico"},
        {"codigo": "S-2399", "descricao": "Trabalhador Sem Vínculo - Término", "tipo": "nao_periodico"},
        {"codigo": "S-1200", "descricao": "Remuneração de Trabalhador", "tipo": "periodico"},
        {"codigo": "S-1210", "descricao": "Pagamentos de Rendimentos", "tipo": "periodico"},
        {"codigo": "S-1260", "descricao": "Comercialização da Produção Rural", "tipo": "periodico"},
        {"codigo": "S-1270", "descricao": "Contratação de Trabalhadores Avulsos", "tipo": "periodico"},
        {"codigo": "S-1280", "descricao": "Informações Complementares aos Eventos Periódicos", "tipo": "periodico"},
        {"codigo": "S-1298", "descricao": "Reabertura dos Eventos Periódicos", "tipo": "periodico"},
        {"codigo": "S-1299", "descricao": "Fechamento dos Eventos Periódicos", "tipo": "periodico"},
    ]
    
    return {
        "eventos": eventos,
        "total": len(eventos)
    }

@app.post("/esocial/gerar-xml/{evento}")
async def gerar_xml_esocial(evento: str, dados: dict):
    """Gera XML para evento do eSocial"""
    # Estrutura básica do XML do eSocial
    xml_estrutura = {
        "evento": evento,
        "versao": "S-1.2",
        "ambiente": dados.get("ambiente", "2"),  # 1=Produção, 2=Homologação
        "dados": dados,
        "status": "estrutura_gerada",
        "observacao": "XML será gerado conforme leiaute oficial do eSocial"
    }
    
    return xml_estrutura

if __name__ == "__main__":
    import uvicorn
    port = int(os.environ.get("PEOPLE_PORT", 8004))
    uvicorn.run(app, host="0.0.0.0", port=port)
