<?php
declare(strict_types=1);

session_start();
date_default_timezone_set('America/Guayaquil');

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: 0');

if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') { http_response_code(204); exit; }
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
  http_response_code(405);
  echo json_encode(['success'=>false,'message'=>'Use POST'], JSON_UNESCAPED_UNICODE);
  exit;
}

function jexit(array $p, int $c=200): void { http_response_code($c); echo json_encode($p, JSON_UNESCAPED_UNICODE); exit; }
function now_str(): string { return date('Y-m-d H:i:s'); }

function read_json(): array {
  $raw = file_get_contents('php://input');
  $j = json_decode($raw ?: '[]', true);
  return is_array($j) ? $j : [];
}

// ✅ bind por referencia (evita fallos silenciosos)
function bind_params(mysqli_stmt $stmt, string $types, array $params): void {
  $refs = [];
  foreach ($params as $k => $v) {
    $refs[$k] = $params[$k];
    $refs[$k] = &$refs[$k];
  }
  array_unshift($refs, $types);
  if (!call_user_func_array([$stmt, 'bind_param'], $refs)) {
    throw new RuntimeException('No se pudo bindear parámetros');
  }
}

function make_in(int $n): string { return implode(',', array_fill(0, $n, '?')); }

// ===== Sesión / permisos =====
if (!isset($_SESSION['ingreso']) || $_SESSION['ingreso'] !== 'YES') jexit(['success'=>false,'message'=>'Sin sesión'], 401);
if ((int)($_SESSION['id_rol'] ?? 0) !== 7) jexit(['success'=>false,'message'=>'Permiso denegado'], 403);

$idCoord = (int)($_SESSION['id_coordinador'] ?? 0);
if ($idCoord <= 0) jexit(['success'=>false,'message'=>'Sesión sin coordinador'], 401);

// ===== DB =====
require_once __DIR__ . '/../../conex.php';
$db = $conn ?? null;
if (!$db instanceof mysqli) jexit(['success'=>false,'message'=>'Sin conexión BD'], 500);
mysqli_set_charset($db, 'utf8mb4');
@mysqli_query($db, "SET time_zone='-05:00'");

// ===== Input =====
$in = read_json();

$tipo       = strtoupper(trim((string)($in['tipo'] ?? '')));
$idDestino  = (int)($in['id_destino'] ?? 0);
$tipoPago   = strtolower(trim((string)($in['tipo_pago'] ?? 'efectivo')));

// descuento en %
$descuento_pct = (float)($in['descuento_pct'] ?? ($in['descuento'] ?? 0));
if (!is_finite($descuento_pct)) $descuento_pct = 0;
if ($descuento_pct < 0) $descuento_pct = 0;
if ($descuento_pct > 100) $descuento_pct = 100;

$codigos = $in['codigos'] ?? [];
if (!is_array($codigos)) $codigos = [];

if (!in_array($tipo, ['PV','CAN'], true)) jexit(['success'=>false,'message'=>'tipo inválido (PV|CAN)'], 422);
if ($idDestino <= 0) jexit(['success'=>false,'message'=>'id_destino requerido'], 422);
if (!in_array($tipoPago, ['efectivo','credito'], true)) jexit(['success'=>false,'message'=>'tipo_pago inválido'], 422);

// Normaliza códigos
$clean = [];
foreach ($codigos as $c) {
  $s = trim((string)$c);
  $s = preg_replace('/\s+/', '', $s);
  if ($s !== '') $clean[] = $s;
}
$clean = array_values(array_unique($clean));
if (count($clean) < 1) jexit(['success'=>false,'message'=>'Lista de códigos vacía'], 422);
if (count($clean) > 800) jexit(['success'=>false,'message'=>'Máximo 800 códigos'], 422);

$fecha = now_str();

mysqli_begin_transaction($db);

try {
  // ===== validar destino =====
  if ($tipo === 'PV') {
    $st = mysqli_prepare($db, "SELECT idusuario FROM tbr_usuario WHERE idusuario=? AND activo=1 AND condicion=1 LIMIT 1");
    if (!$st) throw new RuntimeException('SQL destino PV error');
    bind_params($st, "i", [$idDestino]);
    mysqli_stmt_execute($st);
    mysqli_stmt_store_result($st);
    $ok = (mysqli_stmt_num_rows($st) > 0);
    mysqli_stmt_close($st);
    if (!$ok) { mysqli_rollback($db); jexit(['success'=>false,'message'=>'Punto de venta inválido o inactivo'], 422); }
  } else {
    $st = mysqli_prepare($db, "SELECT id FROM tbr_canillita WHERE id=? AND activo=1 LIMIT 1");
    if (!$st) throw new RuntimeException('SQL destino CAN error');
    bind_params($st, "i", [$idDestino]);
    mysqli_stmt_execute($st);
    mysqli_stmt_store_result($st);
    $ok = (mysqli_stmt_num_rows($st) > 0);
    mysqli_stmt_close($st);
    if (!$ok) { mysqli_rollback($db); jexit(['success'=>false,'message'=>'Canillita inválido o inactivo'], 422); }
  }

  // ===== 1) Obtener registros de códigos (para clasificar) =====
  $ph = make_in(count($clean));
  $sql = "
    SELECT codigo, COALESCE(valor,0) valor,
           COALESCE(estado,0) estado,
           COALESCE(anulado,0) anulado,
           COALESCE(id_usuario,0) id_usuario,
           COALESCE(id_canillita,0) id_canillita,
           COALESCE(id_coordinador,0) id_coordinador
    FROM tbr_raspadita
    WHERE codigo IN ($ph)
  ";
  $stmtE = mysqli_prepare($db, $sql);
  if (!$stmtE) throw new RuntimeException('SQL existencia error');

  bind_params($stmtE, str_repeat('s', count($clean)), $clean);
  mysqli_stmt_execute($stmtE);
  $resE = mysqli_stmt_get_result($stmtE);

  $map = [];
  while ($r = mysqli_fetch_assoc($resE)) $map[(string)$r['codigo']] = $r;
  mysqli_stmt_close($stmtE);

  $no_encontrados = [];
  $no_disponibles = [];
  $para_asignar = [];

  foreach ($clean as $c) {
    if (!isset($map[$c])) { $no_encontrados[] = $c; continue; }

    $r = $map[$c];
    $esMio = ((int)$r['id_coordinador'] === $idCoord);
    $libre = ((int)$r['estado'] === 1)
      && ((int)$r['anulado'] !== 1)
      && ((int)$r['id_usuario'] === 0)
      && ((int)$r['id_canillita'] === 0);

    if (!$esMio || !$libre) { $no_disponibles[] = $c; continue; }
    $para_asignar[] = $c;
  }

  if (count($para_asignar) < 1) {
    mysqli_rollback($db);
    jexit([
      'success'=>false,
      'message'=>'Ningún código disponible para asignar',
      'enviados'=>count($clean),
      'asignados'=>[],
      'no_encontrados'=>$no_encontrados,
      'no_disponibles'=>$no_disponibles
    ], 409);
  }

  // ===== 2) UPDATE (estado=2 en PV y CAN) =====
  $ph2 = make_in(count($para_asignar));

  if ($tipo === 'PV') {
    $sqlUp = "
      UPDATE tbr_raspadita
      SET id_usuario=?, id_canillita=0, estado=2, fecha_hora=?
      WHERE id_coordinador=?
        AND COALESCE(anulado,0) <> 1
        AND estado=1
        AND COALESCE(id_usuario,0)=0
        AND COALESCE(id_canillita,0)=0
        AND codigo IN ($ph2)
    ";
  } else {
    $sqlUp = "
      UPDATE tbr_raspadita
      SET id_canillita=?, id_usuario=0, estado=2, fecha_hora=?
      WHERE id_coordinador=?
        AND COALESCE(anulado,0) <> 1
        AND estado=1
        AND COALESCE(id_usuario,0)=0
        AND COALESCE(id_canillita,0)=0
        AND codigo IN ($ph2)
    ";
  }

  $stmtU = mysqli_prepare($db, $sqlUp);
  if (!$stmtU) throw new RuntimeException('SQL update asignar error');

  $typesU = "isi" . str_repeat("s", count($para_asignar));
  $paramsU = array_merge([$idDestino, $fecha, $idCoord], $para_asignar);
  bind_params($stmtU, $typesU, $paramsU);

  mysqli_stmt_execute($stmtU);
  mysqli_stmt_close($stmtU);

  // ===== 3) Re-consulta asignados reales =====
  $asignados = [];
  if ($tipo === 'PV') {
    $sqlChk = "SELECT codigo FROM tbr_raspadita WHERE codigo IN ($ph2) AND id_usuario=? AND estado=2";
  } else {
    $sqlChk = "SELECT codigo FROM tbr_raspadita WHERE codigo IN ($ph2) AND id_canillita=? AND estado=2";
  }
  $stmtC = mysqli_prepare($db, $sqlChk);
  if (!$stmtC) throw new RuntimeException('SQL check asignados error');

  $typesC = str_repeat('s', count($para_asignar)) . "i";
  $paramsC = array_merge($para_asignar, [$idDestino]);
  bind_params($stmtC, $typesC, $paramsC);

  mysqli_stmt_execute($stmtC);
  $resC = mysqli_stmt_get_result($stmtC);
  while ($rr = mysqli_fetch_assoc($resC)) $asignados[] = (string)$rr['codigo'];
  mysqli_stmt_close($stmtC);

  // ===== 4) Totales reales por SUM(valor) =====
  $subtotal = 0.0;
  $detalle_asignados = [];

  if (count($asignados) > 0) {
    $ph3 = make_in(count($asignados));
    $sqlDet = "SELECT codigo, COALESCE(valor,0) valor FROM tbr_raspadita WHERE codigo IN ($ph3) ORDER BY codigo";
    $stmtD = mysqli_prepare($db, $sqlDet);
    if (!$stmtD) throw new RuntimeException('SQL detalle valores error');

    bind_params($stmtD, str_repeat('s', count($asignados)), $asignados);
    mysqli_stmt_execute($stmtD);
    $resD = mysqli_stmt_get_result($stmtD);

    while ($row = mysqli_fetch_assoc($resD)) {
      $v = (float)$row['valor'];
      $detalle_asignados[] = ['codigo'=>(string)$row['codigo'], 'valor'=>$v];
      $subtotal += $v;
    }
    mysqli_stmt_close($stmtD);
  }

  $descuento_val = $subtotal * ($descuento_pct / 100.0);
  $total = $subtotal - $descuento_val;
  if ($total < 0) $total = 0;

  // ===== 5) Crédito => sumar saldo =====
  $saldo_sumado = false;
  $saldo_target = null;
  $nuevo_saldo = null;
  $saldo_warning = null;

  if ($tipoPago === 'credito' && $total > 0 && count($asignados) > 0) {

    if ($tipo === 'CAN') {
      $stSaldo = mysqli_prepare($db, "UPDATE tbr_canillita SET saldo = COALESCE(saldo,0) + ? WHERE id=? LIMIT 1");
      if (!$stSaldo) throw new RuntimeException('SQL update saldo CAN error');
      bind_params($stSaldo, "di", [$total, $idDestino]);
      mysqli_stmt_execute($stSaldo);
      mysqli_stmt_close($stSaldo);

      $stGet = mysqli_prepare($db, "SELECT COALESCE(saldo,0) saldo FROM tbr_canillita WHERE id=? LIMIT 1");
      if ($stGet) {
        bind_params($stGet, "i", [$idDestino]);
        mysqli_stmt_execute($stGet);
        $r = mysqli_stmt_get_result($stGet);
        $nuevo_saldo = (float)(mysqli_fetch_assoc($r)['saldo'] ?? 0);
        mysqli_stmt_close($stGet);
      }

      $saldo_sumado = true;
      $saldo_target = 'CAN';

    } else {
      // PV: solo si existe columna saldo
      $hasSaldo = false;
      $chk = mysqli_prepare($db, "
        SELECT 1
        FROM information_schema.COLUMNS
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = 'tbr_usuario'
          AND COLUMN_NAME = 'saldo'
        LIMIT 1
      ");
      if ($chk) {
        mysqli_stmt_execute($chk);
        mysqli_stmt_store_result($chk);
        $hasSaldo = (mysqli_stmt_num_rows($chk) > 0);
        mysqli_stmt_close($chk);
      }

      if ($hasSaldo) {
        $stSaldoPv = mysqli_prepare($db, "UPDATE tbr_usuario SET saldo = COALESCE(saldo,0) + ? WHERE idusuario=? LIMIT 1");
        if (!$stSaldoPv) throw new RuntimeException('SQL update saldo PV error');
        bind_params($stSaldoPv, "di", [$total, $idDestino]);
        mysqli_stmt_execute($stSaldoPv);
        mysqli_stmt_close($stSaldoPv);

        $stGetPv = mysqli_prepare($db, "SELECT COALESCE(saldo,0) saldo FROM tbr_usuario WHERE idusuario=? LIMIT 1");
        if ($stGetPv) {
          bind_params($stGetPv, "i", [$idDestino]);
          mysqli_stmt_execute($stGetPv);
          $r = mysqli_stmt_get_result($stGetPv);
          $nuevo_saldo = (float)(mysqli_fetch_assoc($r)['saldo'] ?? 0);
          mysqli_stmt_close($stGetPv);
        }

        $saldo_sumado = true;
        $saldo_target = 'PV';
      } else {
        $saldo_warning = "No se sumó saldo en PV porque tbr_usuario no tiene columna 'saldo'.";
      }
    }
  }

  mysqli_commit($db);

  jexit([
    'success'=>true,
    'message'=>'Asignación realizada',
    'tipo'=>$tipo,
    'id_destino'=>$idDestino,
    'fecha_hora'=>$fecha,

    'enviados'=>count($clean),
    'asignadas'=>count($asignados),
    'asignados'=>$asignados,
    'detalle_asignados'=>$detalle_asignados,
    'no_encontrados'=>$no_encontrados,
    'no_disponibles'=>$no_disponibles,

    'tipo_pago'=>$tipoPago,
    'subtotal'=>$subtotal,
    'descuento_pct'=>$descuento_pct,
    'descuento_val'=>$descuento_val,
    'total'=>$total,

    'saldo_sumado'=>$saldo_sumado,
    'saldo_target'=>$saldo_target,
    'nuevo_saldo'=>$nuevo_saldo,
    'saldo_warning'=>$saldo_warning
  ], 200);

} catch (Throwable $e) {
  mysqli_rollback($db);
  jexit(['success'=>false,'message'=>'Error', 'detail'=>$e->getMessage()], 500);
}