<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);

require_once(dirname(__DIR__) . '/config/db.php');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
header('Content-Type: application/json; charset=utf-8');

$cdempresaLogada = (int)($_SESSION['cdempresa'] ?? 1);

function safeJson($data) {
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

/**
 * Calcular valores por mês a partir de v_realizado_conta_mes.
 * Sempre SOMA todas as contas selecionadas.
 */
function calcularValoresMes(PDO $pdo, int $cdempresa, int $anoref, string $operador, array $contas): array {
    $meses = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
    $resultado = array_fill_keys($meses, 0.0);
    if (empty($contas)) return $resultado;

    $phC = implode(',', array_fill(0, count($contas), '?'));
    $sql = "SELECT mesref, COALESCE(SUM(valor_mes), 0) AS total_mes
              FROM back.v_realizado_conta_mes
             WHERE cdempresa = ? AND anoref = ? AND cdcontacontabil IN ($phC)
             GROUP BY mesref";
    $params = array_merge([$cdempresa, $anoref], $contas);
    $st = $pdo->prepare($sql);
    $st->execute($params);

    while ($r = $st->fetch(PDO::FETCH_ASSOC)) {
        $mi = (int)$r['mesref'];
        if ($mi >= 1 && $mi <= 12) {
            $resultado[$meses[$mi - 1]] = round((float)$r['total_mes'], 4);
        }
    }
    return $resultado;
}

/**
 * Aplicar operador entre dois valores: a [op] b
 */
function aplicarOperadorCalc(float $a, string $operador, float $b): float {
    return match ($operador) {
        '+' => $a + $b,
        '-' => $a - $b,
        '*' => $a * $b,
        '/' => ($b != 0) ? $a / $b : 0,
        default => $a + $b,
    };
}

/**
 * Recalcular e gravar valores calculados de uma linha.
 * Fórmula: _calc[mês] = soma_contas(mês) [operador] valor_digitado(mês)
 */
function recalcularValoresLinha(PDO $pdo, int $cdindvalor, int $cdempresa): void {
    $mesesCols = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];

    // Ler operador, anoref e valores manuais
    $colsManuais = implode(', ', array_map(fn($m) => in_array($m, ['set','out']) ? "\"$m\"" : $m, $mesesCols));
    $st = $pdo->prepare("SELECT operador, anoref, $colsManuais FROM back.indicador_valor WHERE cdindvalor = :id AND cdempresa = :emp");
    $st->execute([':id' => $cdindvalor, ':emp' => $cdempresa]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) return;

    $stC = $pdo->prepare("SELECT cdcontacontabil FROM back.indicador_conta WHERE cdindvalor = :id ORDER BY cdcontacontabil");
    $stC->execute([':id' => $cdindvalor]);
    $contas = array_map('intval', $stC->fetchAll(PDO::FETCH_COLUMN));
    if (empty($contas)) return;

    $operador = $row['operador'] ?: '+';
    $anoref = (int)$row['anoref'];
    $configVals = calcularValoresMes($pdo, $cdempresa, $anoref, $operador, $contas);

    // _calc = config [operador] digitado
    $sets = [];
    $params = [':id' => $cdindvalor];
    foreach ($mesesCols as $m) {
        $manual = (float)($row[$m] ?? 0);
        $config = (float)($configVals[$m] ?? 0);
        $calc = round(aplicarOperadorCalc($config, $operador, $manual), 4);
        $sets[] = "{$m}_calc = :{$m}_c";
        $params[":{$m}_c"] = $calc;
    }
    $pdo->prepare("UPDATE back.indicador_valor SET " . implode(', ', $sets) . " WHERE cdindvalor = :id")->execute($params);
}

try {
    $acao = $_GET['ajax'] ?? null;

    // ==============================================
    // 🔹 LISTAR GRUPOS DE INDICADORES
    // ==============================================
    if ($acao === 'listar_grupos') {
        $rows = $pdo->query("SELECT cdgrupo, dsgrupo, ordem FROM back.grupo_indicador WHERE flativo = 0 ORDER BY ordem NULLS LAST, dsgrupo")->fetchAll(PDO::FETCH_ASSOC);
        safeJson(['ok' => true, 'data' => $rows]);
    }

    // ==============================================
    // 🔹 CRIAR GRUPO DE INDICADOR
    // ==============================================
    if ($acao === 'criar_grupo') {
        $dados = json_decode(file_get_contents('php://input'), true);
        $dsgrupo = trim($dados['dsgrupo'] ?? '');
        if ($dsgrupo === '') safeJson(['ok' => false, 'msg' => '❌ Informe o nome do grupo.']);
        if (mb_strlen($dsgrupo) > 200) safeJson(['ok' => false, 'msg' => '❌ Nome do grupo muito longo (máx 200).']);

        // Check duplicate
        $chk = $pdo->prepare("SELECT 1 FROM back.grupo_indicador WHERE LOWER(dsgrupo) = LOWER(:ds) AND flativo = 0");
        $chk->execute([':ds' => $dsgrupo]);
        if ($chk->fetchColumn()) safeJson(['ok' => false, 'msg' => '❌ Já existe um grupo com este nome.']);

        $st = $pdo->prepare("INSERT INTO back.grupo_indicador (dsgrupo) VALUES (:ds) RETURNING cdgrupo");
        $st->execute([':ds' => $dsgrupo]);
        $cdgrupo = (int)$st->fetchColumn();
        safeJson(['ok' => true, 'msg' => '✅ Grupo criado.', 'cdgrupo' => $cdgrupo, 'dsgrupo' => $dsgrupo]);
    }

    // ==============================================
    // 🔹 LISTAR INDICADORES
    // ==============================================
    if ($acao === 'listar_indicadores') {
        $sql = "SELECT i.cdindicador, i.nome, i.descricao, i.tipo, i.mascara, i.mascara_calc,
                       i.flativo, i.ordem, i.dthrcriacao, i.cdgrupo, g.dsgrupo
                  FROM back.indicador i
                  LEFT JOIN back.grupo_indicador g ON g.cdgrupo = i.cdgrupo
              ORDER BY i.ordem NULLS LAST, i.cdindicador DESC";
        $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
        safeJson(['ok' => true, 'data' => $rows]);
    }

    // ==============================================
    // 🔹 SALVAR INDICADOR (novo)
    // ==============================================
    if ($acao === 'salvar_indicador') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $nome     = trim($dados['nome'] ?? '');
        $descricao = trim($dados['descricao'] ?? '');
        $tipo     = trim($dados['tipo'] ?? 'estatico');
        $mascara  = trim($dados['mascara'] ?? 'inteiro');
        $mascaraCalc = trim($dados['mascara_calc'] ?? '');
        $ordem    = isset($dados['ordem']) && $dados['ordem'] !== '' ? (int)$dados['ordem'] : null;
        $cdgrupo  = isset($dados['cdgrupo']) && $dados['cdgrupo'] !== '' && $dados['cdgrupo'] !== null ? (int)$dados['cdgrupo'] : null;

        if ($nome === '') safeJson(['ok' => false, 'msg' => '❌ Informe o nome do indicador.']);
        if (!in_array($tipo, ['estatico', 'calculado'])) safeJson(['ok' => false, 'msg' => '❌ Tipo inválido.']);
        if (!in_array($mascara, ['inteiro', 'moeda', 'percentual'])) safeJson(['ok' => false, 'msg' => '❌ Máscara inválida.']);
        if ($mascaraCalc !== '' && !in_array($mascaraCalc, ['inteiro', 'moeda', 'percentual'])) safeJson(['ok' => false, 'msg' => '❌ Máscara calculado inválida.']);

        $empresas   = $dados['empresas'] ?? [];
        $exercicios = $dados['exercicios'] ?? [];
        $valores    = $dados['valores'] ?? [];

        $pdo->beginTransaction();

        $sql = "INSERT INTO back.indicador (nome, descricao, tipo, mascara, mascara_calc, ordem, cdgrupo, flativo)
                VALUES (:nome, :descricao, :tipo, :mascara, :mascara_calc, :ordem, :cdgrupo, 0)
                RETURNING cdindicador";
        $stmt = $pdo->prepare($sql);
        $stmt->execute([
            ':nome'         => $nome,
            ':descricao'    => $descricao ?: null,
            ':tipo'         => $tipo,
            ':mascara'      => $mascara,
            ':mascara_calc' => ($tipo === 'calculado' && $mascaraCalc !== '') ? $mascaraCalc : null,
            ':ordem'        => $ordem,
            ':cdgrupo'      => $cdgrupo
        ]);
        $cdNovo = (int)$stmt->fetchColumn();

        // Empresas
        if (!empty($empresas)) {
            $stIns = $pdo->prepare("INSERT INTO back.indicador_empresa (cdindicador, cdempresa) VALUES (:ind, :emp)");
            foreach ($empresas as $empId) {
                $stIns->execute([':ind' => $cdNovo, ':emp' => (int)$empId]);
            }
        }

        // Exercícios + valores (empresa logada)
        $mesesCols = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
        if (!empty($exercicios)) {
            foreach ($exercicios as $anoref) {
                $anoInt = (int)$anoref;
                $valKey = (string)$anoInt;
                $valRow = $valores[$valKey] ?? null;

                $colsList = 'cdindicador, cdempresa, anoref, ' . implode(', ', array_map(fn($m) => in_array($m, ['set','out']) ? "\"$m\"" : $m, $mesesCols));
                $phList = ':ind, :emp, :ano, ' . implode(', ', array_map(fn($m) => ":$m", $mesesCols));
                $params = [':ind' => $cdNovo, ':emp' => $cdempresaLogada, ':ano' => $anoInt];
                foreach ($mesesCols as $m) {
                    $params[":$m"] = (float)($valRow[$m] ?? 0);
                }
                $pdo->prepare("INSERT INTO back.indicador_valor ($colsList) VALUES ($phList) ON CONFLICT (cdindicador, cdempresa, anoref) DO NOTHING")->execute($params);
            }
        }

        $pdo->commit();
        safeJson(['ok' => true, 'msg' => '✅ Indicador criado com sucesso.', 'cdindicador' => $cdNovo]);
    }

    // ==============================================
    // 🔹 OBTER INDICADOR
    // ==============================================
    if ($acao === 'obter_indicador') {
        $id = (int)($_GET['cdindicador'] ?? 0);
        if ($id <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);

        $sql = "SELECT cdindicador, nome, descricao, tipo, mascara, mascara_calc, ordem, cdgrupo
                  FROM back.indicador WHERE cdindicador = :id";
        $stmt = $pdo->prepare($sql);
        $stmt->execute([':id' => $id]);
        $indicador = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$indicador) safeJson(['ok' => false, 'msg' => '❌ Indicador não encontrado.']);

        // Empresas
        $stEmps = $pdo->prepare("SELECT cdempresa FROM back.indicador_empresa WHERE cdindicador = :id ORDER BY cdempresa");
        $stEmps->execute([':id' => $id]);
        $indicador['empresas'] = array_map('intval', $stEmps->fetchAll(PDO::FETCH_COLUMN));

        // Exercícios (apenas empresa logada)
        $stExerc = $pdo->prepare("SELECT DISTINCT anoref FROM back.indicador_valor WHERE cdindicador = :id AND cdempresa = :emp ORDER BY anoref");
        $stExerc->execute([':id' => $id, ':emp' => $cdempresaLogada]);
        $indicador['exercicios'] = array_map('intval', $stExerc->fetchAll(PDO::FETCH_COLUMN));

        safeJson(['ok' => true, 'data' => $indicador]);
    }

    // ==============================================
    // 🔹 ATUALIZAR INDICADOR
    // ==============================================
    if ($acao === 'atualizar_indicador') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $cdindicador = (int)($dados['cdindicador'] ?? 0);
        $nome     = trim($dados['nome'] ?? '');
        $descricao = trim($dados['descricao'] ?? '');
        $tipo     = trim($dados['tipo'] ?? 'estatico');
        $mascara  = trim($dados['mascara'] ?? 'inteiro');
        $mascaraCalc = trim($dados['mascara_calc'] ?? '');
        $ordem    = isset($dados['ordem']) && $dados['ordem'] !== '' ? (int)$dados['ordem'] : null;
        $cdgrupo  = isset($dados['cdgrupo']) && $dados['cdgrupo'] !== '' && $dados['cdgrupo'] !== null ? (int)$dados['cdgrupo'] : null;

        if ($cdindicador <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);
        if ($nome === '') safeJson(['ok' => false, 'msg' => '❌ Informe o nome do indicador.']);
        if (!in_array($tipo, ['estatico', 'calculado'])) safeJson(['ok' => false, 'msg' => '❌ Tipo inválido.']);
        if (!in_array($mascara, ['inteiro', 'moeda', 'percentual'])) safeJson(['ok' => false, 'msg' => '❌ Máscara inválida.']);
        if ($mascaraCalc !== '' && !in_array($mascaraCalc, ['inteiro', 'moeda', 'percentual'])) safeJson(['ok' => false, 'msg' => '❌ Máscara calculado inválida.']);

        $empresas = $dados['empresas'] ?? [];

        $pdo->beginTransaction();

        $sql = "UPDATE back.indicador
                   SET nome = :nome, descricao = :descricao, tipo = :tipo,
                       mascara = :mascara, mascara_calc = :mascara_calc, ordem = :ordem,
                       cdgrupo = :cdgrupo, dthredicao = CURRENT_TIMESTAMP
                 WHERE cdindicador = :id";
        $pdo->prepare($sql)->execute([
            ':nome'         => $nome,
            ':descricao'    => $descricao ?: null,
            ':tipo'         => $tipo,
            ':mascara'      => $mascara,
            ':mascara_calc' => ($tipo === 'calculado' && $mascaraCalc !== '') ? $mascaraCalc : null,
            ':ordem'        => $ordem,
            ':cdgrupo'      => $cdgrupo,
            ':id'           => $cdindicador
        ]);

        // Empresas
        $pdo->prepare("DELETE FROM back.indicador_empresa WHERE cdindicador = :id")->execute([':id' => $cdindicador]);
        if (!empty($empresas)) {
            $stIns = $pdo->prepare("INSERT INTO back.indicador_empresa (cdindicador, cdempresa) VALUES (:ind, :emp)");
            foreach ($empresas as $empId) {
                $stIns->execute([':ind' => $cdindicador, ':emp' => (int)$empId]);
            }
        }

        // Exercícios novos (empresa logada)
        $exercicios = $dados['exercicios'] ?? [];
        if (!empty($exercicios)) {
            foreach ($exercicios as $anoref) {
                $pdo->prepare("INSERT INTO back.indicador_valor (cdindicador, cdempresa, anoref) VALUES (:ind, :emp, :ano) ON CONFLICT (cdindicador, cdempresa, anoref) DO NOTHING")
                    ->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => (int)$anoref]);
            }
        }

        // Auto-calcular linhas configuradas (tipo calculado)
        if ($tipo === 'calculado') {
            $stLinhas = $pdo->prepare("SELECT cdindvalor FROM back.indicador_valor WHERE cdindicador = :ind AND cdempresa = :emp");
            $stLinhas->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada]);
            while ($linha = $stLinhas->fetch(PDO::FETCH_ASSOC)) {
                recalcularValoresLinha($pdo, (int)$linha['cdindvalor'], $cdempresaLogada);
            }
        }

        $pdo->commit();
        safeJson(['ok' => true, 'msg' => '✅ Indicador atualizado com sucesso.']);
    }

    // ==============================================
    // 🔹 TOGGLE ATIVO/INATIVO
    // ==============================================
    if ($acao === 'toggle_indicador') {
        $id = (int)($_POST['cdindicador'] ?? 0);
        if ($id <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);
        $pdo->prepare("UPDATE back.indicador SET flativo = CASE WHEN flativo = 0 THEN 1 ELSE 0 END WHERE cdindicador = :id")->execute([':id' => $id]);
        safeJson(['ok' => true, 'msg' => '✅ Status alterado.']);
    }

    // ==============================================
    // 🔹 EXCLUIR INDICADOR
    // ==============================================
    if ($acao === 'excluir_indicador') {
        $id = (int)($_POST['cdindicador'] ?? 0);
        if ($id <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);
        $pdo->prepare("DELETE FROM back.indicador WHERE cdindicador = :id")->execute([':id' => $id]);
        safeJson(['ok' => true, 'msg' => '🗑️ Indicador excluído com sucesso.']);
    }

    // ==============================================
    // 🔹 OBTER VALORES (grid mensal — empresa logada)
    // ==============================================
    if ($acao === 'obter_valores') {
        $cdindicador = (int)($_GET['cdindicador'] ?? 0);
        $anoref      = (int)($_GET['anoref'] ?? 0);
        if ($cdindicador <= 0 || $anoref <= 0) {
            safeJson(['ok' => false, 'msg' => '❌ Parâmetros inválidos.']);
        }

        $sql = 'SELECT cdindvalor, operador,
                       jan, fev, mar, abr, mai, jun, jul, ago, "set", "out", nov, dez,
                       jan_calc, fev_calc, mar_calc, abr_calc, mai_calc, jun_calc,
                       jul_calc, ago_calc, set_calc, out_calc, nov_calc, dez_calc
                  FROM back.indicador_valor
                 WHERE cdindicador = :ind AND cdempresa = :emp AND anoref = :ano';
        $stmt = $pdo->prepare($sql);
        $stmt->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            $pdo->prepare("INSERT INTO back.indicador_valor (cdindicador, cdempresa, anoref) VALUES (:ind, :emp, :ano) ON CONFLICT (cdindicador, cdempresa, anoref) DO NOTHING")
                ->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
            $stmt->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
        }

        // Contas vinculadas a esta linha
        if ($row && $row['cdindvalor']) {
            $stContas = $pdo->prepare("SELECT cdcontacontabil FROM back.indicador_conta WHERE cdindvalor = :id ORDER BY cdcontacontabil");
            $stContas->execute([':id' => (int)$row['cdindvalor']]);
            $row['contas'] = array_map('intval', $stContas->fetchAll(PDO::FETCH_COLUMN));
        } else {
            $row['contas'] = [];
        }

        safeJson(['ok' => true, 'data' => $row]);
    }

    // ==============================================
    // 🔹 SALVAR VALOR INDIVIDUAL (cell blur)
    // ==============================================
    if ($acao === 'salvar_valor') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $cdindvalor = (int)($dados['cdindvalor'] ?? 0);
        $mes        = trim($dados['mes'] ?? '');
        $valor      = isset($dados['valor']) ? (float)$dados['valor'] : 0;

        $mesesValidos = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
        if ($cdindvalor <= 0 || !in_array($mes, $mesesValidos)) {
            safeJson(['ok' => false, 'msg' => '❌ Parâmetros inválidos.']);
        }

        $coluna = in_array($mes, ['set', 'out']) ? "\"$mes\"" : $mes;
        $pdo->prepare("UPDATE back.indicador_valor SET $coluna = :valor WHERE cdindvalor = :id")
            ->execute([':valor' => $valor, ':id' => $cdindvalor]);
        safeJson(['ok' => true]);
    }

    // ==============================================
    // 🔹 SALVAR CONFIGURAÇÃO DA LINHA (operador + contas)
    // ==============================================
    if ($acao === 'salvar_config_linha') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $cdindvalor = (int)($dados['cdindvalor'] ?? 0);
        $operador   = trim($dados['operador'] ?? '+');
        $contas     = $dados['contas'] ?? [];

        if ($cdindvalor <= 0) safeJson(['ok' => false, 'msg' => '❌ ID da linha inválido.']);
        if (!in_array($operador, ['+', '-', '*', '/'])) safeJson(['ok' => false, 'msg' => '❌ Operador inválido.']);

        // Validar contas
        $contaIds = array_map('intval', array_filter($contas));
        if (!empty($contaIds)) {
            $ph = implode(',', array_fill(0, count($contaIds), '?'));
            $check = $pdo->prepare("SELECT cdcontacontabil FROM back.planocontabil WHERE cdcontacontabil IN ($ph)");
            $check->execute($contaIds);
            $existentes = $check->fetchAll(PDO::FETCH_COLUMN);
            $faltando = array_diff($contaIds, array_map('intval', $existentes));
            if (!empty($faltando)) {
                safeJson(['ok' => false, 'msg' => '⚠️ Contas não encontradas: ' . implode(', ', $faltando)]);
            }
        }

        $pdo->beginTransaction();

        // Atualizar operador na linha
        $pdo->prepare("UPDATE back.indicador_valor SET operador = :op WHERE cdindvalor = :id")
            ->execute([':op' => $operador, ':id' => $cdindvalor]);

        // Recriar contas da linha
        $pdo->prepare("DELETE FROM back.indicador_conta WHERE cdindvalor = :id")->execute([':id' => $cdindvalor]);
        if (!empty($contaIds)) {
            $stConta = $pdo->prepare("INSERT INTO back.indicador_conta (cdindvalor, cdcontacontabil) VALUES (:val, :conta)");
            foreach ($contaIds as $contaId) {
                $stConta->execute([':val' => $cdindvalor, ':conta' => $contaId]);
            }
        }

        // Atualizar formula no indicador (para compatibilidade com comparativo)
        $stInd = $pdo->prepare("SELECT cdindicador FROM back.indicador_valor WHERE cdindvalor = :id");
        $stInd->execute([':id' => $cdindvalor]);
        $cdind = (int)$stInd->fetchColumn();
        if ($cdind > 0 && !empty($contaIds)) {
            $formula = implode(" $operador ", $contaIds);
            $pdo->prepare("UPDATE back.indicador SET formula = :f WHERE cdindicador = :id")
                ->execute([':f' => $formula, ':id' => $cdind]);
        }

        // Recalcular valores da linha a partir da MV
        recalcularValoresLinha($pdo, $cdindvalor, $cdempresaLogada);

        $pdo->commit();
        safeJson(['ok' => true, 'msg' => '✅ Configuração salva e valores calculados.']);
    }

    // ==============================================
    // 🔹 OBTER CONFIGURAÇÃO DA LINHA
    // ==============================================
    if ($acao === 'obter_config_linha') {
        $cdindvalor = (int)($_GET['cdindvalor'] ?? 0);
        if ($cdindvalor <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);

        $stOp = $pdo->prepare("SELECT operador FROM back.indicador_valor WHERE cdindvalor = :id");
        $stOp->execute([':id' => $cdindvalor]);
        $operador = $stOp->fetchColumn() ?: '+';

        $stContas = $pdo->prepare("SELECT cdcontacontabil FROM back.indicador_conta WHERE cdindvalor = :id ORDER BY cdcontacontabil");
        $stContas->execute([':id' => $cdindvalor]);
        $contas = array_map('intval', $stContas->fetchAll(PDO::FETCH_COLUMN));

        safeJson(['ok' => true, 'operador' => $operador, 'contas' => $contas]);
    }

    // ==============================================
    // 🔹 LISTAR EXERCÍCIOS (empresa logada)
    // ==============================================
    if ($acao === 'listar_exercicios') {
        $sql = "SELECT DISTINCT anoref FROM back.exercicio WHERE flativo = 0 AND cdempresa = :emp ORDER BY anoref DESC";
        $stmt = $pdo->prepare($sql);
        $stmt->execute([':emp' => $cdempresaLogada]);
        $rows = $stmt->fetchAll(PDO::FETCH_COLUMN);
        safeJson(['ok' => true, 'data' => array_map('intval', $rows)]);
    }

    // ==============================================
    // 🔹 DESVINCULAR EXERCÍCIO
    // ==============================================
    if ($acao === 'desvincular_exercicio') {
        $dados = json_decode(file_get_contents('php://input'), true);
        $cdindicador = (int)($dados['cdindicador'] ?? 0);
        $anoref      = (int)($dados['anoref'] ?? 0);
        if ($cdindicador <= 0 || $anoref <= 0) safeJson(['ok' => false, 'msg' => '❌ Parâmetros inválidos.']);

        $pdo->prepare("DELETE FROM back.indicador_valor WHERE cdindicador = :ind AND cdempresa = :emp AND anoref = :ano")
            ->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
        safeJson(['ok' => true, 'msg' => '✅ Exercício removido.']);
    }

    // ==============================================
    // 🔹 CALCULAR PRÉVIA (valores calculados da MV)
    // ==============================================
    if ($acao === 'calcular_previa') {
        $cdindvalor = (int)($_GET['cdindvalor'] ?? 0);
        if ($cdindvalor <= 0) safeJson(['ok' => false, 'msg' => '❌ ID inválido.']);

        $mesesCols = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
        $colsManuais = implode(', ', array_map(fn($m) => in_array($m, ['set','out']) ? "\"$m\"" : $m, $mesesCols));

        $st = $pdo->prepare("SELECT operador, anoref, $colsManuais FROM back.indicador_valor WHERE cdindvalor = :id AND cdempresa = :emp");
        $st->execute([':id' => $cdindvalor, ':emp' => $cdempresaLogada]);
        $row = $st->fetch(PDO::FETCH_ASSOC);
        if (!$row) safeJson(['ok' => false, 'msg' => '❌ Linha não encontrada.']);

        $stC = $pdo->prepare("SELECT cdcontacontabil FROM back.indicador_conta WHERE cdindvalor = :id ORDER BY cdcontacontabil");
        $stC->execute([':id' => $cdindvalor]);
        $contas = array_map('intval', $stC->fetchAll(PDO::FETCH_COLUMN));
        if (empty($contas)) safeJson(['ok' => false, 'msg' => '❌ Nenhuma conta configurada nesta linha.']);

        $operador = $row['operador'] ?: '+';
        $anoref = (int)$row['anoref'];
        $configVals = calcularValoresMes($pdo, $cdempresaLogada, $anoref, $operador, $contas);

        // _calc = config [operador] digitado
        $valores = [];
        $sets = [];
        $params = [':id' => $cdindvalor];
        foreach ($mesesCols as $m) {
            $manual = (float)($row[$m] ?? 0);
            $config = (float)($configVals[$m] ?? 0);
            $calc = round(aplicarOperadorCalc($config, $operador, $manual), 4);
            $valores[$m] = $calc;
            $sets[] = "{$m}_calc = :{$m}_c";
            $params[":{$m}_c"] = $calc;
        }
        $pdo->prepare("UPDATE back.indicador_valor SET " . implode(', ', $sets) . " WHERE cdindvalor = :id")->execute($params);

        safeJson(['ok' => true, 'valores' => $valores]);
    }

    // ==============================================
    // 🔹 GET CONTA (para preview)
    // ==============================================
    if ($acao === 'getConta') {
        $id = (int)($_GET['cdcontacontabil'] ?? 0);
        if ($id <= 0) safeJson(['ok' => false]);
        $stmt = $pdo->prepare("SELECT dsconta FROM back.planocontabil WHERE cdcontacontabil = :id");
        $stmt->execute([':id' => $id]);
        $ds = $stmt->fetchColumn();
        safeJson(['ok' => (bool)$ds, 'dsconta' => $ds ?: null]);
    }

    // ==============================================
    // 🔹 CLONAR EXERCÍCIO (copiar config de operador+contas)
    // ==============================================
    if ($acao === 'clonar_exercicio') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $cdindicador      = (int)($dados['cdindicador'] ?? 0);
        $cdindvalorOrigem  = (int)($dados['cdindvalor_origem'] ?? 0);
        $anorefDestino     = (int)($dados['anoref_destino'] ?? 0);

        if (!$cdindicador || !$cdindvalorOrigem || !$anorefDestino)
            safeJson(['ok' => false, 'msg' => '❌ Parâmetros incompletos.']);

        // Verificar se a origem existe e pertence ao indicador
        $stmtOrig = $pdo->prepare("SELECT cdindvalor, operador FROM back.indicador_valor WHERE cdindvalor = :id AND cdindicador = :ind AND cdempresa = :emp");
        $stmtOrig->execute([':id' => $cdindvalorOrigem, ':ind' => $cdindicador, ':emp' => $cdempresaLogada]);
        $origem = $stmtOrig->fetch(PDO::FETCH_ASSOC);
        if (!$origem) safeJson(['ok' => false, 'msg' => '❌ Linha de origem não encontrada.']);

        // Verificar se já existe valor para o destino
        $stmtCheck = $pdo->prepare("SELECT cdindvalor FROM back.indicador_valor WHERE cdindicador = :ind AND cdempresa = :emp AND anoref = :ano");
        $stmtCheck->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anorefDestino]);
        $existente = $stmtCheck->fetchColumn();

        $pdo->beginTransaction();

        if ($existente) {
            $cdindvalorDestino = (int)$existente;
            // Atualizar operador
            $pdo->prepare("UPDATE back.indicador_valor SET operador = :op WHERE cdindvalor = :id")
                ->execute([':op' => $origem['operador'], ':id' => $cdindvalorDestino]);
            // Limpar contas antigas
            $pdo->prepare("DELETE FROM back.indicador_conta WHERE cdindvalor = :id")
                ->execute([':id' => $cdindvalorDestino]);
        } else {
            // Criar novo indicador_valor com zeros
            $pdo->prepare("INSERT INTO back.indicador_valor (cdindicador, cdempresa, anoref, operador, jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez)
                           VALUES (:ind, :emp, :ano, :op, 0,0,0,0,0,0,0,0,0,0,0,0)")
                ->execute([':ind' => $cdindicador, ':emp' => $cdempresaLogada, ':ano' => $anorefDestino, ':op' => $origem['operador']]);
            $cdindvalorDestino = (int)$pdo->lastInsertId('back.indicador_valor_cdindvalor_seq');
        }

        // Copiar contas da origem para o destino
        $stmtContas = $pdo->prepare("SELECT cdcontacontabil FROM back.indicador_conta WHERE cdindvalor = :id ORDER BY cdcontacontabil");
        $stmtContas->execute([':id' => $cdindvalorOrigem]);
        $contas = $stmtContas->fetchAll(PDO::FETCH_COLUMN);

        $stmtInsert = $pdo->prepare("INSERT INTO back.indicador_conta (cdindvalor, cdcontacontabil) VALUES (:val, :conta)");
        foreach ($contas as $conta) {
            $stmtInsert->execute([':val' => $cdindvalorDestino, ':conta' => (int)$conta]);
        }

        $pdo->commit();
        safeJson(['ok' => true, 'msg' => "✅ Configuração clonada para o exercício {$anorefDestino}."]);
    }

    // ==============================================
    // 🔹 LISTAR INDICADORES COMPATÍVEIS PARA CÓPIA
    // ==============================================
    if ($acao === 'listar_indicadores_copiaveis') {
        $cdindicador = (int)($_GET['cdindicador'] ?? 0);
        $anoref       = (int)($_GET['anoref'] ?? 0);
        if (!$cdindicador || !$anoref) safeJson(['ok' => false, 'msg' => '❌ Parâmetros incompletos.']);

        // Obter máscara e grupo do indicador destino
        $stM = $pdo->prepare("SELECT mascara, cdgrupo FROM back.indicador WHERE cdindicador = :id");
        $stM->execute([':id' => $cdindicador]);
        $rowDest = $stM->fetch(PDO::FETCH_ASSOC);
        if (!$rowDest || !$rowDest['mascara']) safeJson(['ok' => false, 'msg' => '❌ Indicador não encontrado.']);
        $mascara = $rowDest['mascara'];
        $cdgrupo = $rowDest['cdgrupo'];

        // Buscar outros indicadores ativos, mesma máscara, tipo estático, mesmo grupo, que tenham valores para esse ano/empresa
        $sql = "SELECT DISTINCT i.cdindicador, i.nome
                FROM back.indicador i
                INNER JOIN back.indicador_empresa ie ON ie.cdindicador = i.cdindicador AND ie.cdempresa = :emp
                INNER JOIN back.indicador_valor iv ON iv.cdindicador = i.cdindicador AND iv.cdempresa = :emp2 AND iv.anoref = :ano
                WHERE i.flativo = 0
                  AND i.mascara = :mascara
                  AND i.tipo = 'estatico'
                  AND i.cdindicador <> :id";
        $params = [':emp' => $cdempresaLogada, ':emp2' => $cdempresaLogada, ':ano' => $anoref, ':mascara' => $mascara, ':id' => $cdindicador];
        if ($cdgrupo) {
            $sql .= " AND i.cdgrupo = :cdgrupo";
            $params[':cdgrupo'] = $cdgrupo;
        }
        $sql .= " ORDER BY i.nome";
        $st = $pdo->prepare($sql);
        $st->execute($params);
        $lista = $st->fetchAll(PDO::FETCH_ASSOC);

        safeJson(['ok' => true, 'indicadores' => $lista, 'mascara' => $mascara]);
    }

    // ==============================================
    // 🔹 COPIAR VALORES DE OUTRO INDICADOR
    // ==============================================
    if ($acao === 'copiar_valores_indicador') {
        $dados = json_decode(file_get_contents('php://input'), true);
        if (!$dados) safeJson(['ok' => false, 'msg' => '❌ Dados inválidos.']);

        $cdindOrigem  = (int)($dados['cdindicador_origem'] ?? 0);
        $cdindDestino = (int)($dados['cdindicador_destino'] ?? 0);
        $anoref       = (int)($dados['anoref'] ?? 0);
        if (!$cdindOrigem || !$cdindDestino || !$anoref)
            safeJson(['ok' => false, 'msg' => '❌ Parâmetros incompletos.']);

        // Validar mesma máscara
        $stM = $pdo->prepare("SELECT cdindicador, mascara FROM back.indicador WHERE cdindicador IN (:o, :d)");
        $stM->execute([':o' => $cdindOrigem, ':d' => $cdindDestino]);
        $mascaras = [];
        foreach ($stM->fetchAll(PDO::FETCH_ASSOC) as $r) $mascaras[$r['cdindicador']] = $r['mascara'];
        if (count($mascaras) < 2) safeJson(['ok' => false, 'msg' => '❌ Indicador(es) não encontrado(s).']);
        if ($mascaras[$cdindOrigem] !== $mascaras[$cdindDestino])
            safeJson(['ok' => false, 'msg' => '❌ Máscaras incompatíveis. Origem: ' . $mascaras[$cdindOrigem] . ', Destino: ' . $mascaras[$cdindDestino]]);

        $mesesCols = ['jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
        $colsSql = implode(', ', array_map(fn($m) => in_array($m, ['set','out']) ? "\"$m\"" : $m, $mesesCols));

        // Ler valores manuais da origem
        $stO = $pdo->prepare("SELECT $colsSql FROM back.indicador_valor WHERE cdindicador = :ind AND cdempresa = :emp AND anoref = :ano");
        $stO->execute([':ind' => $cdindOrigem, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
        $origem = $stO->fetch(PDO::FETCH_ASSOC);
        if (!$origem) safeJson(['ok' => false, 'msg' => '❌ Valores de origem não encontrados para este exercício.']);

        // Ler valores manuais do destino
        $stD = $pdo->prepare("SELECT cdindvalor, $colsSql FROM back.indicador_valor WHERE cdindicador = :ind AND cdempresa = :emp AND anoref = :ano");
        $stD->execute([':ind' => $cdindDestino, ':emp' => $cdempresaLogada, ':ano' => $anoref]);
        $destino = $stD->fetch(PDO::FETCH_ASSOC);
        if (!$destino) safeJson(['ok' => false, 'msg' => '❌ Exercício de destino não encontrado. Adicione o exercício ao indicador primeiro.']);

        // Copiar: origem != 0 AND destino == 0
        $sets = [];
        $params = [':id' => $destino['cdindvalor']];
        $copiados = 0;
        foreach ($mesesCols as $m) {
            $valOrig = (float)($origem[$m] ?? 0);
            $valDest = (float)($destino[$m] ?? 0);
            if ($valOrig != 0 && $valDest == 0) {
                $col = in_array($m, ['set','out']) ? "\"$m\"" : $m;
                $sets[] = "$col = :{$m}_v";
                $params[":{$m}_v"] = $valOrig;
                $copiados++;
            }
        }

        if (empty($sets)) safeJson(['ok' => true, 'msg' => 'ℹ️ Nenhum valor copiado (origem zerada ou destino já preenchido).', 'copiados' => 0]);

        $pdo->prepare("UPDATE back.indicador_valor SET " . implode(', ', $sets) . " WHERE cdindvalor = :id")->execute($params);

        // If calculado, recalcular
        $stTipo = $pdo->prepare("SELECT tipo FROM back.indicador WHERE cdindicador = :id");
        $stTipo->execute([':id' => $cdindDestino]);
        if ($stTipo->fetchColumn() === 'calculado') {
            recalcularValoresLinha($pdo, (int)$destino['cdindvalor'], $cdempresaLogada);
        }

        safeJson(['ok' => true, 'msg' => "✅ $copiados mês(es) copiado(s) com sucesso.", 'copiados' => $copiados]);
    }

    safeJson(['ok' => false, 'msg' => '❌ Ação não reconhecida.']);

} catch (Exception $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    safeJson(['ok' => false, 'msg' => '❌ Erro: ' . $e->getMessage()]);
}
