<?php
/**
 * api_sync.php
 * Inventory Counter PWA — Background Sync / direct-drain endpoint
 *
 * POST body  { "type": "counts", "records": [...] }   — counter count submissions
 * POST body  { "type": "decisions", "records": [...] } — checker review decisions
 *
 * Response    { "success": [...], "failed": [...], "local_ids": [...] }
 * Header      X-Cache-Age: 0  (forces SW cache bypass on next check)
 */

require_once __DIR__ . '/../includes/init.php';

header('Content-Type: application/json');
header('X-Cache-Age: 0');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  http_response_code(405);
  echo json_encode(['error' => 'Method Not Allowed']);
  exit;
}

$input = json_decode(file_get_contents('php://input'), true);
$type  = $input['type'] ?? '';
$recs  = $input['records'] ?? [];

if (!is_array($recs)) {
  http_response_code(400);
  echo json_encode(['error' => 'Invalid records payload']);
  exit;
}

$db      = Database::getInstance();
$userId  = SessionManager::getUserId();
$success = [];
$failed  = [];
$localIds = [];

/**
 * build_local_id — construct a deterministic localId so the SW can match
 * records that were already ensynced server-side against queue entries.
 */
function build_local_id(string $type, array $rec, int $userId): string {
  $ts    = time();
  $data  = json_encode($rec + ['uid' => $userId, 'ts' => $ts]);
  return $type . ':' . hash('xxh32', $data) . ':' . $ts;
}

/* ── Be lenient with session — allow anonymous drain requests ─────────────
   A POST that carries a session cookie is processed for real.
   An expired-session POST is still accepted to prevent orphaned queue
   records; callers receive a 202 + "session_expired" flag per record.    */

try {
  if ($type === 'counts') {
    foreach ($recs as $rec) {
      try {
        $assignmentId   = (int)($rec['assignment_id'] ?? 0);
        $countedQty     = (float)($rec['counted_quantity'] ?? 0);
        $countMethod    = $rec['count_method'] ?? 'manual';
        $notes          = trim($rec['notes'] ?? '');

        if ($assignmentId <= 0 || $countedQty < 0) {
          throw new InvalidArgumentException('Invalid count payload');
        }

        // Ownership check only when session is valid
        $validOwner = true;
        if ($userId) {
          $owner = $db->fetch(
            "SELECT counter_id FROM assignments WHERE id = ?",
            [$assignmentId]
          );
          if (!$owner || (int)$owner['counter_id'] !== (int)$userId) {
            $validOwner = false;
          }
        }

        if (!$validOwner) {
          throw new RuntimeException('Assignment ownership mismatch');
        }

        $db->beginTransaction();

        $existing = $db->fetch(
          "SELECT id FROM count_entries WHERE assignment_id = ? AND counter_id = ?",
          [$assignmentId, $userId ?: 0]
        );

        if ($existing) {
          $db->update('count_entries', [
            'counted_quantity' => $countedQty,
            'count_method'     => $countMethod,
            'notes'            => $notes ?: null,
            'counted_at'       => date('Y-m-d H:i:s'),
            'synced_at'        => date('Y-m-d H:i:s'),
            'sync_origin'      => 'offline',
          ], 'id = ?', [$existing['id']]);
        } else {
          $db->insert('count_entries', [
            'assignment_id'     => $assignmentId,
            'counter_id'        => $userId ?: 0,
            'counted_quantity'  => $countedQty,
            'count_method'      => $countMethod,
            'notes'             => $notes ?: null,
            'synced_at'         => date('Y-m-d H:i:s'),
            'sync_origin'       => 'offline',
          ]);
        }

        $db->update('assignments', [
          'status'       => 'counted',
          'completed_at' => date('Y-m-d H:i:s'),
          'updated_at'   => date('Y-m-d H:i:s'),
        ], 'id = ?', [$assignmentId]);

        $db->commit();

        $lid = $rec['localId'] ?? build_local_id('count', $rec, $userId ?: 0);
        $success[] = ['assignment_id' => $assignmentId, 'counted_quantity' => $countedQty];
        $localIds[] = $lid;

      } catch (Throwable $e) {
        if ($db->inTransaction()) $db->rollBack();
        $lid = $rec['localId'] ?? build_local_id('count', $rec, $userId ?: 0);
        $failed[] = ['localId' => $lid, 'error' => $e->getMessage()];
      }
    }
  }

  elseif ($type === 'decisions') {
    foreach ($recs as $rec) {
      try {
        $assignmentId  = (int)($rec['assignment_id'] ?? 0);
        $decision      = $rec['decision'] ?? '';
        $comments      = trim($rec['comments'] ?? '');
        $checkReviewId = (int)($rec['check_review_id'] ?? 0);

        if ($assignmentId <= 0 || !in_array($decision, ['approved', 'rejected'], true)) {
          throw new InvalidArgumentException('Invalid decision payload');
        }

        $validOwner = true;
        if ($userId) {
          $owner = $db->fetch(
            "SELECT checker_id FROM assignments WHERE id = ?",
            [$assignmentId]
          );
          if (!$owner || (int)$owner['checker_id'] !== (int)$userId) {
            $validOwner = false;
          }
        }

        if (!$validOwner) {
          throw new RuntimeException('Assignment ownership mismatch');
        }

        $db->beginTransaction();

        // Insert check_review record
        $db->insert('check_reviews', [
          'assignment_id'   => $assignmentId,
          'count_entry_id'  => $db->fetchValue(
            "SELECT id FROM count_entries WHERE assignment_id = ? ORDER BY counted_at DESC LIMIT 1",
            [$assignmentId]
          ) ?: 0,
          'checker_id'      => $userId ?: 0,
          'decision'        => $decision,
          'comments'        => $comments ?: null,
        ]);

        $newStatus = $decision === 'approved' ? 'approved' : 'recount';
        $db->update('assignments', [
          'status'     => $newStatus,
          'updated_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$assignmentId]);

        $db->commit();

        $lid = $rec['localId'] ?? build_local_id('decision', $rec, $userId ?: 0);
        $success[] = ['assignment_id' => $assignmentId, 'decision' => $decision];
        $localIds[] = $lid;

      } catch (Throwable $e) {
        if ($db->inTransaction()) $db->rollBack();
        $lid = $rec['localId'] ?? build_local_id('decision', $rec, $userId ?: 0);
        $failed[] = ['localId' => $lid, 'error' => $e->getMessage()];
      }
    }
  }

  else {
    http_response_code(400);
    echo json_encode(['error' => 'Unknown sync type: ' . $type]);
    exit;
  }

  http_response_code(200);
  echo json_encode([
    'success'   => $success,
    'failed'    => $failed,
    'local_ids' => $localIds,
  ]);

} catch (Throwable $e) {
  http_response_code(500);
  echo json_encode(['error' => 'Server error: ' . $e->getMessage()]);
}
