<?php
namespace PayCal\Connector;

defined('ABSPATH') || exit;

class DashboardClient {
  private const TRANSIENT_TTL = 180;
  private const LAST_GOOD_OPTION = 'paycal_merchant_dashboard_last_good';

  public static function get(bool $force_refresh = false): array {
    $settings = ConnectorStore::get();
    $credentials = self::credentials($settings);
    if (!$credentials['ready']) {
      return [
        'ok' => false,
        'auth_error' => true,
        'stale' => false,
        'data' => [],
        'message' => 'PayCal dashboard credentials are missing. Connect the store with a public key and access token.',
        'last_updated' => '',
      ];
    }

    $cache_key = self::cache_key($settings);
    if ($force_refresh) {
      delete_transient($cache_key);
    }

    if (!$force_refresh) {
      $cached = get_transient($cache_key);
      if (is_array($cached) && !empty($cached['data'])) {
        return [
          'ok' => true,
          'auth_error' => false,
          'stale' => false,
          'data' => $cached['data'],
          'message' => '',
          'last_updated' => (string) ($cached['last_updated'] ?? ''),
        ];
      }
    }

    $url = rtrim((string) $settings['platform_url'], '/') . '/wp-json/paycal/v1/merchant-dashboard';
    if ($force_refresh) {
      $url = add_query_arg('_paycal_refresh', (string) time(), $url);
    }
    $response = wp_remote_get($url, [
      'timeout' => 12,
      'headers' => [
        'Accept' => 'application/json',
        'Cache-Control' => 'no-cache, no-store, must-revalidate',
        'Pragma' => 'no-cache',
        'X-PayCal-Public-Key' => (string) $settings['public_key'],
        'X-PayCal-Token' => (string) $settings['access_token'],
      ],
    ]);

    if (is_wp_error($response)) {
      return self::unavailable($response->get_error_message(), $settings);
    }

    $code = (int) wp_remote_retrieve_response_code($response);
    if ($code === 401 || $code === 403) {
      return [
        'ok' => false,
        'auth_error' => true,
        'stale' => false,
        'data' => [],
        'message' => 'PayCal dashboard access was denied. Check that the API key has merchant_dashboard:read scope.',
        'last_updated' => '',
      ];
    }

    if ($code < 200 || $code >= 300) {
      return self::unavailable('PayCal Platform returned HTTP ' . $code . '.', $settings);
    }

    $decoded = json_decode((string) wp_remote_retrieve_body($response), true);
    if (!is_array($decoded) || empty($decoded['ok'])) {
      return self::unavailable('PayCal Platform returned an unreadable dashboard response.', $settings);
    }

    $data = self::clean_payload($decoded);
    $now = self::fetch_time($data);
    $stored = [
      'data' => $data,
      'last_updated' => $now,
      'cache_key' => $cache_key,
    ];
    set_transient($cache_key, $stored, self::TRANSIENT_TTL);
    update_option(self::LAST_GOOD_OPTION, $stored, false);

    return [
      'ok' => true,
      'auth_error' => false,
      'stale' => false,
      'data' => $data,
      'message' => '',
      'last_updated' => $now,
    ];
  }

  private static function credentials(array $settings): array {
    $ready = !empty($settings['platform_url']) && !empty($settings['public_key']) && !empty($settings['access_token']);
    return ['ready' => $ready];
  }

  private static function unavailable(string $message, array $settings): array {
    $last = get_option(self::LAST_GOOD_OPTION, []);
    if (is_array($last) && !empty($last['data']) && (($last['cache_key'] ?? '') === self::cache_key($settings))) {
      return [
        'ok' => true,
        'auth_error' => false,
        'stale' => true,
        'data' => $last['data'],
        'message' => sanitize_text_field($message),
        'last_updated' => (string) ($last['last_updated'] ?? ''),
      ];
    }

    return [
      'ok' => false,
      'auth_error' => false,
      'stale' => false,
      'data' => [],
      'message' => sanitize_text_field($message),
      'last_updated' => '',
    ];
  }

  private static function cache_key(array $settings): string {
    return 'paycal_merchant_dashboard_' . md5((string) ($settings['platform_url'] ?? '') . '|' . (string) ($settings['public_key'] ?? '') . '|' . hash('sha256', (string) ($settings['access_token'] ?? '')));
  }

  private static function fetch_time(array $data): string {
    $server_time = sanitize_text_field((string) ($data['server_time'] ?? ''));
    return $server_time !== '' ? $server_time : current_time('mysql');
  }

  private static function clean_payload(array $payload): array {
    return [
      'merchant' => self::clean_assoc((array) ($payload['merchant'] ?? []), ['uid', 'business_name', 'status', 'mode']),
      'summary' => self::clean_assoc((array) ($payload['summary'] ?? []), [
        'gross_total',
        'fee_total',
        'net_total',
        'pending_settlement',
        'settled_settlement',
        'ledger_entry_count',
        'settlement_batch_count',
        'currency',
      ]),
      'recent_payments' => self::clean_rows((array) ($payload['recent_payments'] ?? []), [
        'payment_id',
        'order_id',
        'session_id',
        'status',
        'gross_amount',
        'fee_amount',
        'net_amount',
        'currency',
        'created_at',
        'settlement_uid',
        'settlement_status',
        'settlement_reference',
        'invoice_url',
      ]),
      'recent_settlements' => self::clean_rows((array) ($payload['recent_settlements'] ?? []), [
        'settlement_uid',
        'status',
        'gross_amount',
        'fee_amount',
        'net_amount',
        'currency',
        'entry_count',
        'expected_payout_at',
        'settled_at',
        'bank_reference',
        'created_at',
      ]),
      'latest_reconciliation' => self::clean_assoc((array) ($payload['latest_reconciliation'] ?? []), [
        'event_type',
        'match_status',
        'provider',
        'settlement_uid',
        'settlement_reference',
        'bank_reference',
        'created_at',
      ]),
      'server_time' => sanitize_text_field((string) ($payload['server_time'] ?? '')),
    ];
  }

  private static function clean_rows(array $rows, array $keys): array {
    $clean = [];
    foreach (array_slice($rows, 0, 50) as $row) {
      if (is_array($row)) {
        $clean[] = self::clean_assoc($row, $keys);
      }
    }
    return $clean;
  }

  private static function clean_assoc(array $row, array $keys): array {
    $clean = [];
    foreach ($keys as $key) {
      $value = $row[$key] ?? '';
      $clean[$key] = is_scalar($value) ? sanitize_text_field((string) $value) : '';
    }
    return $clean;
  }
}
