<?php
require_once(dirname(__DIR__) . '/config/db.php');

ini_set('display_errors', '0');
error_reporting(E_ALL);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

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

$empresaId = $_SESSION['empresa']['id'] ?? null;
if (!$empresaId) {
    json_out(['ok' => false, 'msg' => 'Sessão expirada. Faça login novamente.'], 401);
}

function json_out($arr, $code = 200) {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($arr, JSON_UNESCAPED_UNICODE);
    exit;
}

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

try {
    switch ($acao) {
        case 'listar': listar(); break;
        case 'salvar': salvar(); break;
        case 'toggle': toggle(); break;
        case 'oficial': oficial(); break;
        case 'toggle_mes': toggleMes(); break;
        case 'excluir': excluir(); break;
        default:
            json_out(['ok' => false, 'msg' => 'Ação inválida'], 400);
    }
} catch (Exception $e) {
    json_out(['ok' => false, 'msg' => 'Erro: ' . $e->getMessage()], 500);
}

/* ============================================================
 * LISTAR EXERCÍCIOS
 * ============================================================ */
function listar() {
    global $pdo, $empresaId;

    $status = $_GET['status'] ?? 'todas';
    $busca  = trim($_GET['busca'] ?? '');
    $order  = $_GET['order'] ?? 'anoref';
    $dir    = strtolower($_GET['dir'] ?? 'desc') === 'asc' ? 'asc' : 'desc';
    $limit  = isset($_GET['limit']) ? (int)$_GET['limit'] : 100;
    $page   = isset($_GET['page']) ? (int)$_GET['page'] : 1;
    if ($limit <= 0) $limit = 100;
    if ($page  <= 0) $page  = 1;
    $offset = ($page - 1) * $limit;

    $orderWhitelist = ['cdexercicio','anoref','descricao','floficial'];
    if (!in_array($order, $orderWhitelist)) $order = 'anoref';

    $params = [':emp' => $empresaId];
    $whereBusca = '';
    if ($busca !== '') {
        $whereBusca .= " AND (CAST(e.anoref AS TEXT) ILIKE :busca OR e.descricao ILIKE :busca)";
        $params[':busca'] = "%$busca%";
    }

    $sql = "
        SELECT e.*
          FROM back.exercicio e
         WHERE e.cdempresa = :emp
               $whereBusca
      ORDER BY $order $dir
         LIMIT $limit OFFSET $offset
    ";
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $exercicios = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // Meses do exerciciodet
    $meses = [];
    if ($exercicios) {
        $ids = array_column($exercicios, 'cdexercicio');
        $in = implode(',', array_fill(0, count($ids), '?'));
        $stmtM = $pdo->prepare("SELECT cdexercicio, mesref, flaberto, dtfechamento FROM back.exerciciodet WHERE cdexercicio IN ($in) ORDER BY mesref");
        $stmtM->execute($ids);
        while ($m = $stmtM->fetch(PDO::FETCH_ASSOC)) {
            $meses[$m['cdexercicio']][] = $m;
        }
    }

    foreach ($exercicios as &$e) {
        $e['meses'] = $meses[$e['cdexercicio']] ?? [];
    }

    json_out(['ok' => true, 'data' => $exercicios]);
}

/* ============================================================
 * SALVAR (CRIAR/EDITAR)
 * ============================================================ */
function salvar() {
    global $pdo, $empresaId;
    $data = json_decode(file_get_contents('php://input'), true);
    if (!$data) json_out(['ok' => false, 'msg' => 'Dados inválidos'], 400);

    $id        = (int)($data['cdexercicio'] ?? 0);
    $anoref    = (int)($data['anoref'] ?? 0);
    $descricao = trim($data['descricao'] ?? '');
    $floficial = !empty($data['floficial']) ? 1 : 0;

    if ($anoref < 1900 || $anoref > 3000) json_out(['ok' => false, 'msg' => 'Ano inválido'], 400);
    if ($descricao === '') json_out(['ok' => false, 'msg' => 'Descrição obrigatória'], 400);

    $pdo->beginTransaction();
    try {
                if ($id > 0) {
                        $sql = "UPDATE back.exercicio
                                             SET anoref = :ano, descricao = :desc, floficial = :oficial
                                         WHERE cdexercicio = :id AND cdempresa = :emp";
            $pdo->prepare($sql)->execute([
                ':ano' => $anoref,
                ':desc'=> $descricao,
                ':oficial'=> $floficial,
                ':id' => $id,
                ':emp'=> $empresaId
            ]);
            $msg = '✅ Exercício atualizado';
        } else {
                $sql = "INSERT INTO back.exercicio (anoref, descricao, floficial, flativo, cdempresa)
                    VALUES (:ano, :desc, :oficial, 0, :emp) RETURNING cdexercicio";
            $stmt = $pdo->prepare($sql);
            $stmt->execute([
                ':ano' => $anoref,
                ':desc'=> $descricao,
                ':oficial'=> $floficial,
                ':emp'=> $empresaId
            ]);
            $id = (int)$stmt->fetchColumn();
            // Criar meses 1-12 abertos
            $stmtMes = $pdo->prepare("INSERT INTO back.exerciciodet (cdexercicio, mesref, flaberto) VALUES (:id, :mes, true)");
            for ($m = 1; $m <= 12; $m++) {
                $stmtMes->execute([':id' => $id, ':mes' => $m]);
            }
            $msg = '✅ Exercício criado';
        }

        $pdo->commit();
        json_out(['ok' => true, 'msg' => $msg, 'cdexercicio' => $id]);
    } catch (Exception $e) {
        $pdo->rollBack();
        throw $e;
    }
}

/* ============================================================
 * TOGGLE ATIVO/INATIVO
 * ============================================================ */
function toggle() {
    global $pdo, $empresaId;
    $id = (int)($_POST['cdexercicio'] ?? 0);
    if ($id <= 0) json_out(['ok' => false, 'msg' => 'ID inválido'], 400);

    $pdo->prepare("UPDATE back.exercicio
                      SET flativo = CASE WHEN flativo = 0 THEN 1 ELSE 0 END
                    WHERE cdexercicio = :id AND cdempresa = :emp")
        ->execute([':id' => $id, ':emp' => $empresaId]);

    json_out(['ok' => true, 'msg' => '✅ Status alterado']);
}

/* ============================================================
 * TOGGLE OFICIAL
 * ============================================================ */
function oficial() {
    global $pdo, $empresaId;
    $id = (int)($_POST['cdexercicio'] ?? 0);
    if ($id <= 0) json_out(['ok' => false, 'msg' => 'ID inválido'], 400);

    $pdo->prepare("UPDATE back.exercicio
                      SET floficial = CASE WHEN floficial = 1 THEN 0 ELSE 1 END
                    WHERE cdexercicio = :id AND cdempresa = :emp")
        ->execute([':id' => $id, ':emp' => $empresaId]);

    json_out(['ok' => true, 'msg' => '✅ Oficialidade alterada']);
}

/* ============================================================
 * EXCLUIR EXERCÍCIO (SEM LANÇAMENTOS EM REALIZADO)
 * ============================================================ */
function excluir() {
    global $pdo, $empresaId;
    $id = (int)($_POST['cdexercicio'] ?? 0);
    if ($id <= 0) {
        json_out(['ok' => false, 'msg' => 'ID inválido'], 400);
    }

    $pdo->beginTransaction();
    try {
        // Garante que o exercício pertence à empresa logada
        $stmt = $pdo->prepare('SELECT cdempresa FROM back.exercicio WHERE cdexercicio = :id');
        $stmt->execute([':id' => $id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row || (int)$row['cdempresa'] !== (int)$empresaId) {
            $pdo->rollBack();
            json_out(['ok' => false, 'msg' => 'Exercício não encontrado para esta empresa.'], 404);
        }

        // Verifica se existe qualquer lançamento em realizado para este exercício
        $stmt = $pdo->prepare('SELECT 1 FROM back.realizado WHERE cdempresa = :emp AND cdexercicio = :id LIMIT 1');
        $stmt->execute([':emp' => $empresaId, ':id' => $id]);
        if ($stmt->fetch()) {
            $pdo->rollBack();
            json_out([
                'ok'  => false,
                'msg' => 'Não é possível excluir: existe(m) lançamento(s) em realizado para este exercício. Utilize a opção de inativar.'
            ]);
        }

        // Remove períodos e o próprio exercício
        $pdo->prepare('DELETE FROM back.exerciciodet WHERE cdexercicio = :id')->execute([':id' => $id]);
        $pdo->prepare('DELETE FROM back.exercicio WHERE cdexercicio = :id AND cdempresa = :emp')
            ->execute([':id' => $id, ':emp' => $empresaId]);

        $pdo->commit();
        json_out(['ok' => true, 'msg' => '✅ Exercício excluído com sucesso.']);
    } catch (Exception $e) {
        $pdo->rollBack();
        throw $e;
    }
}

/* ============================================================
 * ABRIR / FECHAR MÊS DO EXERCÍCIO
 * ============================================================ */
function toggleMes() {
    global $pdo, $empresaId;
    $id  = (int)($_POST['cdexercicio'] ?? 0);
    $mes = (int)($_POST['mesref'] ?? 0);
    if ($id <= 0 || $mes < 1 || $mes > 12) {
        json_out(['ok' => false, 'msg' => 'Parâmetros inválidos'], 400);
    }

    // Garante que exercício pertence à empresa logada
    $stmt = $pdo->prepare('SELECT cdempresa FROM back.exercicio WHERE cdexercicio = :id');
    $stmt->execute([':id' => $id]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$row || (int)$row['cdempresa'] !== (int)$empresaId) {
        json_out(['ok' => false, 'msg' => 'Exercício não encontrado'], 404);
    }

    // Busca registro do mês
    $stmt = $pdo->prepare('SELECT cdexerciciodet, flaberto FROM back.exerciciodet WHERE cdexercicio = :id AND mesref = :mes');
    $stmt->execute([':id' => $id, ':mes' => $mes]);
    $det = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($det) {
        // Alterna o status diretamente no banco, evitando passar boolean como parâmetro
        // flaberto: true (aberto) -> false (fechado) e vice-versa
        // dtfechamento: NOW() quando estava aberto (fechando agora), NULL quando estava fechado (reabrindo)
        $stmtUpd = $pdo->prepare("UPDATE back.exerciciodet
                                     SET flaberto = NOT flaberto,
                                         dtfechamento = CASE WHEN flaberto THEN NOW() ELSE NULL END,
                                         dthedicao = NOW()
                                   WHERE cdexerciciodet = :det
                                RETURNING flaberto");
        $stmtUpd->execute([':det' => $det['cdexerciciodet']]);
        $novo = $stmtUpd->fetchColumn();
    } else {
        // Para exercícios antigos sem registro, cria como aberto
        $novo = true;
        $pdo->prepare('INSERT INTO back.exerciciodet (cdexercicio, mesref, flaberto) VALUES (:id, :mes, TRUE)')
            ->execute([':id' => $id, ':mes' => $mes]);
    }

    // $novo pode vir como 't'/'f' do Postgres; converte para booleano simples para o JS
    $novoBool = ($novo === true || $novo === 1 || $novo === 't' || $novo === '1');

    json_out(['ok' => true, 'msg' => '✅ Período atualizado', 'flaberto' => $novoBool]);
}
