<?php
declare(strict_types=1);
ini_set('display_errors', 0);
error_reporting(E_ALL);
ini_set('log_errors', 1);

require_once(dirname(__DIR__) . "/config/db.php");
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

header("Content-Type: application/json; charset=UTF-8");

function out($arr){
    echo json_encode($arr, JSON_UNESCAPED_UNICODE);
    exit;
}

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

$empresa = $_SESSION["empresa"]["id"] ?? null;

if (!$empresa) {
    out(["ok" => false, "msg" => "Sessão expirada"]);
}

$acao = $_GET["ajax"] ?? null;

/* ============================================================
   FUNÇÃO REUTILIZÁVEL: RECALCULAR TOTAIS DO PAI
   (Apenas para a empresa logada - evita gargalo desnecessário)
============================================================ */
function recalcularTotaisPai($pdo, $cdorcamentodet, $cdempresa) {
    $sql = "
        UPDATE back.orcamentodet od
        SET 
            jan = (SELECT COALESCE(SUM(jan),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            fev = (SELECT COALESCE(SUM(fev),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            mar = (SELECT COALESCE(SUM(mar),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            abr = (SELECT COALESCE(SUM(abr),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            mai = (SELECT COALESCE(SUM(mai),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            jun = (SELECT COALESCE(SUM(jun),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            jul = (SELECT COALESCE(SUM(jul),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            ago = (SELECT COALESCE(SUM(ago),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            \"set\" = (SELECT COALESCE(SUM(\"set\"),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            \"out\" = (SELECT COALESCE(SUM(\"out\"),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            nov = (SELECT COALESCE(SUM(nov),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            dez = (SELECT COALESCE(SUM(dez),0) FROM back.orcamentodetfilho WHERE cdorcamentodet = od.cdorcamentodet),
            dtalteracao = now()
        WHERE cdorcamentodet = :id
          AND od.cdempresa = :emp
    ";

    $st = $pdo->prepare($sql);
    $result = $st->execute([":id" => $cdorcamentodet, ":emp" => $cdempresa]);
    
    // Refresh da materialized view após consolidação
    if ($result) {
        try {
            $pdo->exec("REFRESH MATERIALIZED VIEW CONCURRENTLY back.v_orcado_conta_mes");
        } catch (Exception $e) {
            // Log silencioso - refresh não deve interromper a operação
            error_log("Erro ao atualizar v_orcado_conta_mes: " . $e->getMessage());
        }
    }
    
    return $result;
}

/* ============================================================
   CABEÇALHO
============================================================ */
if ($acao === "cabecalho") {

    $cdorcamentodet = (int)($_GET["cdorcamentodet"] ?? 0);
    if ($cdorcamentodet <= 0) out(["ok" => false]);

    $sql = "
        SELECT 
            od.cdorcamento,
            od.cdcontacontabil,
            o.cdexercicio,
            o.cdcentrocusto,
            e.anoref,
            c.dscentro,
            m.simbolo,
            m.formato,
            pc.dsconta,
            pc.cdconta
        FROM back.orcamentodet od
        JOIN back.orcamento o ON o.cdorcamento = od.cdorcamento
        JOIN back.exercicio e ON e.cdexercicio = o.cdexercicio
        JOIN back.centro_custo c ON c.cdcentrocusto = o.cdcentrocusto
        JOIN back.empresa emp ON emp.cdempresa = o.cdempresa
        JOIN back.moeda m ON m.cdmoeda = emp.cdmoeda
        JOIN back.planocontabil pc ON pc.cdcontacontabil = od.cdcontacontabil
        WHERE od.cdorcamentodet = :id
    ";

    $st = $pdo->prepare($sql);
    $st->execute([":id" => $cdorcamentodet]);
    $r = $st->fetch(PDO::FETCH_ASSOC);

    out([
        "ok" => true,
        "cdorcamento"      => $r["cdorcamento"],
        "cdcontacontabil"  => $r["cdcontacontabil"],
        "exercicio"        => $r["anoref"],
        "centrocusto"      => $r["dscentro"],
        "moeda"            => $r["simbolo"],
        "simbolo"          => $r["simbolo"],
        "formato"          => $r["formato"],
        "conta_desc"       => $r["dsconta"],
        "conta_cd"         => $r["cdconta"]
    ]);
}

/* ============================================================
   LISTAR LINHAS FILHAS
============================================================ */
if ($acao === "listar") {

    $cdorcamentodet = (int)($_GET["cdorcamentodet"] ?? 0);
    if ($cdorcamentodet <= 0) out([]);

    $sql = "
        SELECT 
            f.cdorcamentodetfilho AS id,
            f.dsorigem,
            f.dslancamento AS descricao,
            f.cdpessoa,
            f.dsobs,
            f.jan, f.fev, f.mar, f.abr, f.mai, f.jun,
            f.jul, f.ago, f.set, f.out, f.nov, f.dez,
            p.dspessoa AS pessoa_nome
        FROM back.orcamentodetfilho f
        LEFT JOIN back.pessoa p ON p.cdpessoa = f.cdpessoa
        WHERE f.cdorcamentodet = :id
        ORDER BY f.cdorcamentodetfilho ASC
    ";

    $st = $pdo->prepare($sql);
    $st->execute([":id" => $cdorcamentodet]);
    $linhas = $st->fetchAll(PDO::FETCH_ASSOC);

    foreach ($linhas as &$l) {
        $l["meses"] = [
            (float)$l["jan"], (float)$l["fev"], (float)$l["mar"], (float)$l["abr"],
            (float)$l["mai"], (float)$l["jun"], (float)$l["jul"], (float)$l["ago"],
            (float)$l["set"], (float)$l["out"], (float)$l["nov"], (float)$l["dez"],
        ];
    }

    out($linhas);
}

/* ============================================================
   CRIAR LINHA — GRAVANDO cdempresa
============================================================ */
if ($acao === "criar_linha") {

    $cdorcamentodet = (int)($_POST["cdorcamentodet"] ?? 0);
    if ($cdorcamentodet <= 0) out(["ok" => false, "msg" => "Erro ao criar"]);

    $sql = "
        INSERT INTO back.orcamentodetfilho
        (cdorcamentodet, dsorigem, dslancamento, cdpessoa, dtinicio, dtfim, cdempresa)
        VALUES (:p1, 'MANUAL', '', NULL, NULL, NULL, :empresa)
        RETURNING cdorcamentodetfilho
    ";

    $st = $pdo->prepare($sql);
    $st->execute([
        ":p1"      => $cdorcamentodet,
        ":empresa" => $empresa
    ]);

    $id = $st->fetchColumn();

    // Recalcular totais do pai (por consistência, embora nova linha tenha zeros)
    recalcularTotaisPai($pdo, $cdorcamentodet, $empresa);

    out(["ok" => true, "id" => $id]);
}

/* ============================================================
   ATUALIZAR CAMPO
============================================================ */
if ($acao === "atualizar_campo") {

    $id    = (int)($_POST["id"] ?? 0);
    $campo = $_POST["campo"] ?? "";
    $valor = $_POST["valor"] ?? "";
    $limparPessoa = isset($_POST["limparPessoa"]);

    $permitidos = ["dsorigem","descricao","dsobs","cdpessoa"];
    if (!in_array($campo, $permitidos)) out(["ok" => false, "msg" => "Campo inválido"]);

    $map = [
        "descricao" => "dslancamento",
        "dsorigem"  => "dsorigem",
        "dsobs"     => "dsobs",
        "cdpessoa"  => "cdpessoa"
    ];
    $coluna = $map[$campo];

    if ($limparPessoa) {
        $pdo->prepare("UPDATE back.orcamentodetfilho SET cdpessoa = NULL WHERE cdorcamentodetfilho = ?")
            ->execute([$id]);
        out(["ok" => true]);
    }

    $sql = "UPDATE back.orcamentodetfilho 
            SET $coluna = :v, dtalteracao = now() 
            WHERE cdorcamentodetfilho = :id";

    $st = $pdo->prepare($sql);
    $st->execute([":v"=>$valor,":id"=>$id]);

    out(["ok" => true]);
}

/* ============================================================
   ATUALIZAR MÊS
============================================================ */
if ($acao === "atualizar_mes") {

    $id = (int)($_POST["id"] ?? 0);
    $indice = (int)($_POST["indice"] ?? -1);
    $valor = (float)($_POST["valor"] ?? 0);

    $meses = ["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"];

    if ($indice < 0 || $indice > 11) out(["ok" => false]);
    $coluna = $meses[$indice];

    $sql = "UPDATE back.orcamentodetfilho 
            SET $coluna = :v, dtalteracao = now() 
            WHERE cdorcamentodetfilho = :id";

    $st = $pdo->prepare($sql);
    $st->execute([":v"=>$valor,":id"=>$id]);

    // Buscar o cdorcamentodet pai para recalcular totais
    $sqlPai = "SELECT cdorcamentodet FROM back.orcamentodetfilho WHERE cdorcamentodetfilho = :id";
    $stPai = $pdo->prepare($sqlPai);
    $stPai->execute([":id" => $id]);
    $pai = $stPai->fetch(PDO::FETCH_ASSOC);

    if ($pai) {
        recalcularTotaisPai($pdo, $pai["cdorcamentodet"], $empresa);
    }

    out(["ok" => true]);
}

/* ============================================================
   EXCLUIR
============================================================ */
if ($acao === "excluir") {

    $id = (int)($_POST["id"] ?? 0);

    // Buscar o cdorcamentodet antes de deletar para recalcular depois
    $sqlBusca = "SELECT cdorcamentodet FROM back.orcamentodetfilho WHERE cdorcamentodetfilho = :id";
    $stBusca = $pdo->prepare($sqlBusca);
    $stBusca->execute([":id"=>$id]);
    $registro = $stBusca->fetch(PDO::FETCH_ASSOC);
    $cdorcamentodet = $registro ? (int)$registro["cdorcamentodet"] : null;

    $sql = "DELETE FROM back.orcamentodetfilho 
            WHERE cdorcamentodetfilho = :id";

    $st = $pdo->prepare($sql);
    $st->execute([":id"=>$id]);

    // Recalcular totais do pai após deletar
    if ($cdorcamentodet) {
        recalcularTotaisPai($pdo, $cdorcamentodet, $empresa);
    }

    out(["ok" => true]);
}

/* ============================================================
   LISTAR PESSOAS
============================================================ */
if ($acao === "listar_pessoas") {

    $sql = "
        SELECT cdpessoa AS id, dspessoa AS nome, documento , telefone , cidade
        FROM back.pessoa
        WHERE flativo = 0 AND (flfuncionario = TRUE OR flfornecedor = TRUE)
        ORDER BY dspessoa
        LIMIT 500
    ";

    $lista = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);

    out($lista);
}
/* ============================================================
   AUTOMAÇÃO DA LINHA
============================================================ */
if ($acao === "automacao") {

    $idFilho = (int)($_POST["id"] ?? 0);
    $tipo    = $_POST["tipo"] ?? "";

    if ($idFilho <= 0 || !$tipo) {
        out(["ok" => false, "msg" => "Parâmetros inválidos."]);
    }

    /* ---------------------------------------------------------
       BUSCAR CONTEXTO COMPLETO DA LINHA
    --------------------------------------------------------- */
    $sqlCtx = "
        SELECT 
            f.cdorcamentodetfilho,
            f.cdorcamentodet,
            od.cdcontacontabil,
            o.cdorcamento,
            o.cdcentrocusto,
            e.anoref,
            emp.cdempresa
        FROM back.orcamentodetfilho f
        JOIN back.orcamentodet od  ON od.cdorcamentodet = f.cdorcamentodet
        JOIN back.orcamento o      ON o.cdorcamento     = od.cdorcamento
        JOIN back.exercicio e      ON e.cdexercicio     = o.cdexercicio
        JOIN back.empresa emp      ON emp.cdempresa     = o.cdempresa
        WHERE f.cdorcamentodetfilho = :id
    ";

    $st = $pdo->prepare($sqlCtx);
    $st->execute([":id" => $idFilho]);
    $ctx = $st->fetch(PDO::FETCH_ASSOC);

    if (!$ctx) out(["ok" => false, "msg" => "Linha não encontrada."]);

    $cdorcamentodet  = (int)$ctx["cdorcamentodet"];
    $cdconta         = $ctx["cdcontacontabil"];
    $cdcentrocusto   = $ctx["cdcentrocusto"];
    $anoref          = (int)$ctx["anoref"];
    $cdempresa_ctx   = (int)$ctx["cdempresa"];

    $mesesCols = ["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"];
    $novosValores = array_fill(0, 12, 0.0);

    /* ============================================================
       1) REPETIR VALOR
    ============================================================ */
    if ($tipo === "repetir") {

        $valor = (float)($_POST["valor"] ?? 0);

        foreach ($mesesCols as $i => $c) {
            $novosValores[$i] = $valor;
        }

    /* ============================================================
       2) ZERAR TODOS OS MESES
    ============================================================ */
    } elseif ($tipo === "zerar") {

        // já está tudo zerado em $novosValores

    /* ============================================================
       3) % SOBRE ANO ANTERIOR (ORÇADO OU REALIZADO)
    ============================================================ */
    } elseif ($tipo === "percentual_anterior") {

        $base       = $_POST["base"] ?? "orcado";
        $percentual = (float)($_POST["percentual"] ?? 0);
        $fat        = 1 + ($percentual / 100.0);

        if ($base === "orcado") {

            $sqlAnt = "
                SELECT 
                    f.jan, f.fev, f.mar, f.abr, f.mai, f.jun,
                    f.jul, f.ago, f.set, f.out, f.nov, f.dez
                FROM back.orcamentodet od
                JOIN back.orcamento o      ON o.cdorcamento     = od.cdorcamento
                JOIN back.exercicio e      ON e.cdexercicio     = o.cdexercicio
                JOIN back.orcamentodetfilho f ON f.cdorcamentodet = od.cdorcamentodet
                WHERE o.cdempresa     = :emp
                  AND o.cdcentrocusto = :cc
                  AND e.anoref        = :anoAnterior
                  AND od.cdcontacontabil = :conta
                ORDER BY f.cdorcamentodetfilho
                LIMIT 1
            ";

            $stAnt = $pdo->prepare($sqlAnt);
            $stAnt->execute([
                ":emp"        => $cdempresa_ctx,
                ":cc"         => $cdcentrocusto,
                ":anoAnterior"=> $anoref - 1,
                ":conta"      => $cdconta
            ]);
            $ant = $stAnt->fetch(PDO::FETCH_ASSOC);

            if (!$ant) {
                out(["ok" => false, "msg" => "Não foi encontrado ORÇADO do ano anterior para esta conta."]);
            }

            foreach ($mesesCols as $i => $c) {
                $novosValores[$i] = ((float)$ant[$c]) * $fat;
            }

        } else {

            $sqlReal = "
                SELECT 
                    r.mesref,
                    SUM(r.valor) as valor_realizado
                FROM back.realizado r
                WHERE r.cdempresa       = :emp
                  AND r.cdplanocontabil = :conta
                  AND r.anoref          = :anoAnterior
                  AND r.flcancelado     = 0
                GROUP BY r.mesref
                ORDER BY r.mesref
            ";

            $stReal = $pdo->prepare($sqlReal);
            $stReal->execute([
                ":emp"        => $cdempresa_ctx,
                ":conta"      => $cdconta,
                ":anoAnterior"=> $anoref - 1
            ]);

            $linReal = $stReal->fetchAll(PDO::FETCH_ASSOC);
            if (!$linReal) {
                out(["ok" => false, "msg" => "Não foi encontrado REALIZADO do ano anterior para esta conta."]);
            }

            $mapMes = [];
            foreach ($linReal as $r) {
                $mapMes[(int)$r["mesref"]] = (float)$r["valor_realizado"];
            }

            foreach ($mesesCols as $i => $c) {
                $mesIndex = $i + 1;
                $novosValores[$i] = ($mapMes[$mesIndex] ?? 0) * $fat;
            }
        }

    /* ============================================================
       4) PCIDEAL / RECEITA MATRIZ
    ============================================================ */
    } elseif ($tipo === "pcideal_receita") {

        $percentualManual = isset($_POST["percentual_manual"]) && $_POST["percentual_manual"] !== ""
            ? (float)$_POST["percentual_manual"]
            : null;

        $receitaManual = isset($_POST["receita_manual"]) && $_POST["receita_manual"] !== ""
            ? (float)$_POST["receita_manual"]
            : null;

        /* --- Buscar PCIDEAL da conta atual --- */
        $sqlPC = "
            SELECT flnatureza, COALESCE(pcideal,0) AS pcideal
            FROM back.planocontabil
            WHERE cdcontacontabil = :conta
            LIMIT 1
        ";
        $stPC = $pdo->prepare($sqlPC);
        $stPC->execute([":conta" => $cdconta]);
        $pc = $stPC->fetch(PDO::FETCH_ASSOC);

       $flnatureza = $_POST["natureza"] ?? $pc["flnatureza"];
        $pcideal    = (float)$pc["pcideal"];

        // escolha do percentual
        $percentual = $percentualManual !== null ? $percentualManual : $pcideal;
        $fator = $percentual / 100.0;

        /* --- Buscar CONTA MATRIZ (receita base) --- */
        $sqlMat = "
            SELECT cdcontacontabil
            FROM back.orcamentodet
            WHERE flmatriz = TRUE and flativo = 0
              AND flnatureza = :nat
            LIMIT 1
        ";
        $stMat = $pdo->prepare($sqlMat);
        $stMat->execute([":nat" => $flnatureza]);
        $mat = $stMat->fetch(PDO::FETCH_ASSOC);

        if (!$mat) {
            out(["ok" => false, "msg" => "Conta matriz de Natureza {$flnatureza} não Definida ."]);
        }

        $cdcontaMatriz = $mat["cdcontacontabil"];

        /* --- Buscar receita base no orçamento atual --- */
        $sqlRec = "
            SELECT 
                od.jan, od.fev, od.mar, od.abr, od.mai, od.jun,
                od.jul, od.ago, od.set, od.out, od.nov, od.dez
            FROM back.orcamentodet od
            JOIN back.orcamento o  ON o.cdorcamento = od.cdorcamento
            JOIN back.exercicio e  ON e.cdexercicio = o.cdexercicio
            WHERE o.cdempresa     = :emp
              AND o.cdcentrocusto = :cc
              AND e.anoref        = :ano
              AND od.cdcontacontabil = :contaMatriz
			  and od.flmatriz is true 
			  and od.flativo = 0
            LIMIT 1
        ";

        $stRec = $pdo->prepare($sqlRec);
        $stRec->execute([
            ":emp"        => $cdempresa_ctx,
            ":cc"         => $cdcentrocusto,
            ":ano"        => $anoref,
            ":contaMatriz"=> $cdcontaMatriz
        ]);

        $rec = $stRec->fetch(PDO::FETCH_ASSOC);

        // RECEITA MANUAL DIGITADA (usa somente se > 0)
if ($receitaManual !== null && $receitaManual > 0) {

    $baseMes = $receitaManual;

    foreach ($mesesCols as $i => $c) {
        $novosValores[$i] = $baseMes * $fator;
    }

// RECEITA DO BANCO (somente quando não foi digitado valor manual)
} elseif ($rec) {

    foreach ($mesesCols as $i => $c) {
        $baseRec = (float)$rec[$c];
        $novosValores[$i] = $baseRec * $fator;
    }

// SEM RECEITA NO BANCO E SEM MANUAL → EXIGIR DIGITAÇÃO
} else {
    out([
        "ok"    => false,
        "msg"   => "Nenhuma receita encontrada. Informe receita manual.",
        "codigo"=> "SEM_RECEITA_BASE"
    ]);
}


    } else {
        out(["ok" => false, "msg" => "Tipo de automação inválido."]);
    }

    /* ============================================================
       ATUALIZA OS MESES NO BANCO
    ============================================================ */
    $sqlUpd = "
        UPDATE back.orcamentodetfilho
        SET 
            jan = :jan, fev = :fev, mar = :mar, abr = :abr, mai = :mai, jun = :jun,
            jul = :jul, ago = :ago, \"set\" = :set, \"out\" = :out, nov = :nov, dez = :dez,
            dtalteracao = now()
        WHERE cdorcamentodetfilho = :id
    ";

    $paramsUpd = [
        ":jan"=>$novosValores[0], ":fev"=>$novosValores[1], ":mar"=>$novosValores[2],
        ":abr"=>$novosValores[3], ":mai"=>$novosValores[4], ":jun"=>$novosValores[5],
        ":jul"=>$novosValores[6], ":ago"=>$novosValores[7], ":set"=>$novosValores[8],
        ":out"=>$novosValores[9], ":nov"=>$novosValores[10], ":dez"=>$novosValores[11],
        ":id"=>$idFilho
    ];

    $stUpd = $pdo->prepare($sqlUpd);
    $stUpd->execute($paramsUpd);

    // Recalcular totais do pai imediatamente após atualizar
    recalcularTotaisPai($pdo, $cdorcamentodet, $cdempresa_ctx);

    out(["ok" => true]);
}
/* ============================================================
   RECALCULAR TOTAL DO PAI
============================================================ */
if ($acao === "recalcular") {

    $id = (int)($_POST["id"] ?? 0);
    if ($id <= 0) out(["ok" => false]);

    recalcularTotaisPai($pdo, $id, $empresa);
    out(["ok" => true]);
}

/* ============================================================
   RETORNAR PCIDEAL PARA O MODAL (USADO AO ABRIR O BOTÃO ⋮)
============================================================ */
if ($acao === "pcideal_da_conta") {

    $idFilho = (int)($_GET["id"] ?? 0);
    if ($idFilho <= 0) out(["ok" => false]);

    $sql = "
        SELECT pc.pcideal
        FROM back.orcamentodetfilho f
        JOIN back.orcamentodet od ON od.cdorcamentodet = f.cdorcamentodet
        JOIN back.planocontabil pc ON pc.cdcontacontabil = od.cdcontacontabil
        WHERE f.cdorcamentodetfilho = :id
        LIMIT 1
    ";

    $st = $pdo->prepare($sql);
    $st->execute([":id" => $idFilho]);
    $pc = $st->fetch(PDO::FETCH_ASSOC);

    out([
        "ok"      => true,
        "pcideal" => $pc ? (float)$pc["pcideal"] : null
    ]);
}

/* ============================================================
   AÇÃO DESCONHECIDA
============================================================ */
out(["ok" => false, "msg" => "Ação inválida"]);
