<?php
if (!defined('ABSPATH')) exit; // Exit if accessed directly

use AC_SYNC\Includes\Classes\Api\Action_Wear_Api_Route;
use AC_SYNC\Includes\Classes\Api\Action_Wear_API_Response as ApiResponse;
use AC_SYNC\Includes\Classes\Sql\Action_Wear_Sql_Manager;
use AC_SYNC\Includes\Classes\Sql\Action_Wear_Sql_Versioning;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Runner as JobRunner;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Queue as JobQueue;
use AC_SYNC\Includes\Classes\Api\Action_Wear_API;
use AC_SYNC\Includes\Classes\Differential\Entities\Action_Wear_Price;
use AC_SYNC\Includes\Classes\Differential\Entities\Action_Wear_Quantity;
use AC_SYNC\Includes\Classes\Differential\Entities\Action_Wear_Product_Differential as DiffCatalog;

$route = new Action_Wear_Api_Route("/get_diagnostics");
$route->setMethods("GET");
$route->setCallback(function () {
  $response = new ApiResponse();
  global $wpdb;

  $checks = [

    // 1. Tables present
    'tables_present' => function () use ($wpdb) {
      $expected = array_merge(Action_Wear_Sql_Manager::TABLES, ['actionwear_jobs']);
      $missing = [];
      foreach ($expected as $table) {
        $full = $wpdb->prefix . $table;
        $found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $full));
        if (!$found) {
          $missing[] = $table;
        }
      }
      if (empty($missing)) {
        return ['status' => 'pass', 'message' => 'All plugin tables are present.', 'details' => ['tables_checked' => count($expected)]];
      }
      return ['status' => 'fail', 'message' => count($missing) . ' table(s) missing.', 'details' => ['missing' => $missing]];
    },

    // 2. Products count
    'products_count' => function () use ($wpdb) {
      $table = $wpdb->prefix . 'actionwear_products';
      $count = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table}`");
      if ($count > 0) {
        return ['status' => 'pass', 'message' => $count . ' products in archive.', 'details' => ['count' => $count]];
      }
      return ['status' => 'warning', 'message' => 'No products in archive.', 'details' => ['count' => 0]];
    },

    // 3. Images count
    'images_count' => function () use ($wpdb) {
      $table = $wpdb->prefix . 'actionwear_images';
      $count = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table}`");
      if ($count > 0) {
        return ['status' => 'pass', 'message' => $count . ' images in archive.', 'details' => ['count' => $count]];
      }
      return ['status' => 'warning', 'message' => 'No images in archive.', 'details' => ['count' => 0]];
    },

    // 4. Brands count
    'brands_count' => function () use ($wpdb) {
      $table = $wpdb->prefix . 'actionwear_brands';
      $count = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table}`");
      if ($count > 0) {
        return ['status' => 'pass', 'message' => $count . ' brands in archive.', 'details' => ['count' => $count]];
      }
      return ['status' => 'warning', 'message' => 'No brands in archive.', 'details' => ['count' => 0]];
    },

    // 5. Token present
    'token_present' => function () {
      $token = get_option('_ACTIONWEAR_TOKEN_CODE');
      if (!empty($token)) {
        return ['status' => 'pass', 'message' => 'Authentication token is present.', 'details' => []];
      }
      return ['status' => 'fail', 'message' => 'Authentication token is missing.', 'details' => []];
    },

    // 6. DB version coherence
    'db_version_coherence' => function () {
      $stored = get_option('_ACTIONWEAR_DB_VERSION', '0.0.0');
      $manager = Action_Wear_Sql_Manager::DB_VERSION;
      $versions = array_keys(Action_Wear_Sql_Versioning::REGISTERED_VERSIONS);
      $maxRegistered = !empty($versions) ? end($versions) : '0.0.0';

      if ($stored === $manager && $stored === $maxRegistered) {
        return ['status' => 'pass', 'message' => 'Database version is coherent (' . $stored . ').', 'details' => [
          'stored' => $stored,
          'manager' => $manager,
          'max_registered' => $maxRegistered,
        ]];
      }
      return ['status' => 'fail', 'message' => 'Database version mismatch.', 'details' => [
        'stored' => $stored,
        'manager' => $manager,
        'max_registered' => $maxRegistered,
      ]];
    },

    // 7. Job cron health
    'job_cron_health' => function () {
      $details = [];
      $issues = [];

      // Check cron scheduled
      $nextRun = wp_next_scheduled('actionwear_runner_hook');
      $details['cron_scheduled'] = (bool) $nextRun;
      if (!$nextRun) {
        $issues[] = 'Cron actionwear_runner_hook is not scheduled.';
      }

      // Check heartbeat staleness
      $heartbeat = get_option(JobRunner::HEARTBEAT_KEY, null);
      if ($heartbeat !== null) {
        $age = time() - (int) $heartbeat;
        $details['heartbeat_age_seconds'] = $age;
        $details['heartbeat_stale'] = $age > JobRunner::STALE_THRESHOLD;
      } else {
        $details['heartbeat_age_seconds'] = null;
        $details['heartbeat_stale'] = null;
      }

      // Check runner lock
      $lockActive = (bool) get_option(JobRunner::RUNNER_LOCK_KEY);
      $details['runner_lock_active'] = $lockActive;

      // Check if lock is present but heartbeat is stale (inconsistent)
      if ($lockActive && isset($details['heartbeat_stale']) && $details['heartbeat_stale']) {
        $issues[] = 'Runner lock is active but heartbeat is stale.';
      }

      // Check pending jobs
      $pendingJobs = JobQueue::getJobs(['status' => 'pending'], 1);
      $hasPending = !empty($pendingJobs);
      $details['has_pending_jobs'] = $hasPending;

      if (!empty($issues)) {
        return ['status' => 'fail', 'message' => implode(' ', $issues), 'details' => $details];
      }

      // Warning if runner idle without pending (not an issue, just info)
      if (!$lockActive && $heartbeat === null && !$hasPending) {
        return ['status' => 'warning', 'message' => 'Runner is idle with no pending jobs.', 'details' => $details];
      }

      return ['status' => 'pass', 'message' => 'Cron and job runner are healthy.', 'details' => $details];
    },

    // 8. Hub connectivity
    'hub_connectivity' => function () {
      $jwt = get_option('_ACTIONWEAR_HUB_JWT');
      if (empty($jwt)) {
        return ['status' => 'fail', 'message' => 'Hub JWT token is missing.', 'details' => ['jwt_present' => false, 'ping' => null]];
      }

      try {
        $ping = Action_Wear_API::pingInstance();
      } catch (\Exception $e) {
        $ping = false;
      }

      if ($ping) {
        return ['status' => 'pass', 'message' => 'Hub is reachable.', 'details' => ['jwt_present' => true, 'ping' => true]];
      }
      return ['status' => 'warning', 'message' => 'Hub JWT is present but ping failed.', 'details' => ['jwt_present' => true, 'ping' => false]];
    },

  ];

  // Execute all checks
  $results = [];
  $summary = ['pass' => 0, 'warning' => 0, 'fail' => 0, 'total' => 0];

  foreach ($checks as $id => $check) {
    try {
      $result = $check();
    } catch (\Exception $e) {
      $result = ['status' => 'fail', 'message' => 'Check threw an exception: ' . $e->getMessage(), 'details' => []];
    }
    $result['id'] = $id;
    $results[] = $result;
    $summary[$result['status']] = ($summary[$result['status']] ?? 0) + 1;
    $summary['total']++;
  }

  $response->success([
    'checks' => $results,
    'summary' => $summary,
  ]);
  return $response->getResponse();
});
$route->registerRoute();
