<?php
declare(strict_types=1);

if (!function_exists('app_config')) {
  require_once __DIR__ . '/db.php';
}

function iys_load_config(): array
{
  $cfg = function_exists('app_config') ? app_config() : [];

  $sms = [];
  if (isset($cfg['sms']) && is_array($cfg['sms'])) {
    $sms = $cfg['sms'];
  }
  if (empty($sms)) {
    $smsFile = __DIR__ . '/../config/sms.php';
    if (is_file($smsFile)) {
      $loaded = require $smsFile;
      if (is_array($loaded)) {
        $sms = $loaded;
      }
    }
  }

  $iys = [];
  if (isset($cfg['iys']) && is_array($cfg['iys'])) {
    $iys = $cfg['iys'];
  }
  if (empty($iys) && isset($sms['iys']) && is_array($sms['iys'])) {
    $iys = $sms['iys'];
  }

  $enabledRaw = $iys['enabled'] ?? true;
  $enabled = filter_var($enabledRaw, FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE);
  if ($enabled === null) {
    $enabled = (bool)$enabledRaw;
  }

  return [
    'enabled' => $enabled,
    'endpoint' => (string)($iys['endpoint'] ?? 'https://api.netgsm.com.tr/iys/add'),
    'username' => (string)($iys['username'] ?? ($sms['username'] ?? '')),
    'password' => (string)($iys['password'] ?? ($sms['password'] ?? '')),
    'brand_code' => (string)($iys['brand_code'] ?? ($sms['header'] ?? ($sms['username'] ?? ''))),
    'recipient_type' => strtoupper((string)($iys['recipient_type'] ?? 'BIREYSEL')),
    'channel_type' => strtoupper((string)($iys['channel_type'] ?? 'MESAJ')),
    'consent_source' => strtoupper((string)($iys['consent_source'] ?? 'HS_WEB')),
    'approved_status' => strtoupper((string)($iys['approved_status'] ?? 'ONAY')),
    'rejected_status' => strtoupper((string)($iys['rejected_status'] ?? 'RET')),
    'timeout' => max(5, (int)($iys['timeout'] ?? 30)),
  ];
}

function iys_normalize_phone(string $raw): string
{
  $digits = preg_replace('/\D+/', '', $raw) ?? '';
  if ($digits === '') return '';
  if (str_starts_with($digits, '0090') && strlen($digits) === 14) {
    return substr($digits, 2);
  }
  if (strlen($digits) === 10) return '90' . $digits;
  if (strlen($digits) === 11 && str_starts_with($digits, '0')) return '90' . substr($digits, 1);
  if (strlen($digits) === 12 && str_starts_with($digits, '90')) return $digits;
  return $digits;
}

function iys_ensure_tables(PDO $pdo): void
{
  $pdo->exec("
    CREATE TABLE IF NOT EXISTS iys_sync_state (
      phone_e164 varchar(16) NOT NULL PRIMARY KEY,
      last_status varchar(16) NOT NULL,
      last_channel_type varchar(16) NOT NULL DEFAULT 'MESAJ',
      last_synced_at datetime NOT NULL,
      last_http_code int DEFAULT NULL,
      last_response text DEFAULT NULL,
      updated_at datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  ");

  $pdo->exec("
    CREATE TABLE IF NOT EXISTS iys_sync_logs (
      id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
      phone_raw varchar(32) NOT NULL,
      phone_e164 varchar(16) NOT NULL,
      local_status varchar(16) NOT NULL,
      remote_status varchar(16) NOT NULL,
      channel_type varchar(16) NOT NULL,
      source varchar(64) NOT NULL DEFAULT 'manual',
      event_ref varchar(128) DEFAULT NULL,
      request_json longtext DEFAULT NULL,
      response_text longtext DEFAULT NULL,
      http_code int DEFAULT NULL,
      success tinyint(1) NOT NULL DEFAULT 0,
      error varchar(255) DEFAULT NULL,
      created_at datetime NOT NULL DEFAULT current_timestamp(),
      PRIMARY KEY (id),
      KEY idx_phone (phone_e164),
      KEY idx_created (created_at),
      KEY idx_success (success)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  ");
}

function iys_send_single(
  string $phoneE164,
  string $localStatus,
  string $consentDate = '',
  array $configOverrides = []
): array {
  $cfg = array_merge(iys_load_config(), $configOverrides);

  if (empty($cfg['enabled'])) {
    return [
      'ok' => false,
      'skipped' => true,
      'http_code' => 0,
      'response_body' => '',
      'error' => 'iys_disabled',
      'request_payload' => null,
      'request_endpoint' => (string)($cfg['endpoint'] ?? ''),
      'remote_status' => '',
      'channel_type' => (string)($cfg['channel_type'] ?? 'MESAJ'),
    ];
  }

  $requiredKeys = ['endpoint', 'username', 'password', 'brand_code'];
  foreach ($requiredKeys as $key) {
    if ((string)($cfg[$key] ?? '') === '') {
      return [
        'ok' => false,
        'skipped' => false,
        'http_code' => 0,
        'response_body' => '',
        'error' => 'iys_missing_' . $key,
        'request_payload' => null,
        'request_endpoint' => (string)($cfg['endpoint'] ?? ''),
        'remote_status' => '',
        'channel_type' => (string)($cfg['channel_type'] ?? 'MESAJ'),
      ];
    }
  }

  $localStatus = strtolower(trim($localStatus));
  if ($localStatus !== 'onayli' && $localStatus !== 'onaysiz') {
    return [
      'ok' => false,
      'skipped' => false,
      'http_code' => 0,
      'response_body' => '',
      'error' => 'invalid_local_status',
      'request_payload' => null,
      'request_endpoint' => (string)($cfg['endpoint'] ?? ''),
      'remote_status' => '',
      'channel_type' => (string)($cfg['channel_type'] ?? 'MESAJ'),
    ];
  }

  $phoneE164 = iys_normalize_phone($phoneE164);
  if ($phoneE164 === '') {
    return [
      'ok' => false,
      'skipped' => false,
      'http_code' => 0,
      'response_body' => '',
      'error' => 'invalid_phone',
      'request_payload' => null,
      'request_endpoint' => (string)($cfg['endpoint'] ?? ''),
      'remote_status' => '',
      'channel_type' => (string)($cfg['channel_type'] ?? 'MESAJ'),
    ];
  }

  $remoteStatus = $localStatus === 'onayli'
    ? (string)$cfg['approved_status']
    : (string)$cfg['rejected_status'];
  $channelType = strtoupper((string)$cfg['channel_type']);
  $consentDate = trim($consentDate) !== '' ? trim($consentDate) : date('Y-m-d H:i:s');

  $payload = [[
    'recipient' => $phoneE164,
    'recipientType' => (string)$cfg['recipient_type'],
    'consentDate' => $consentDate,
    'consentSource' => (string)$cfg['consent_source'],
    'status' => $remoteStatus,
    'channelType' => $channelType,
  ]];

  $jsonBody = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
  if (!is_string($jsonBody) || $jsonBody === '') {
    return [
      'ok' => false,
      'skipped' => false,
      'http_code' => 0,
      'response_body' => '',
      'error' => 'json_encode_failed',
      'request_payload' => $payload,
      'request_endpoint' => (string)$cfg['endpoint'],
      'remote_status' => $remoteStatus,
      'channel_type' => $channelType,
    ];
  }

  $url = rtrim((string)$cfg['endpoint'], '?&');
  $query = http_build_query([
    'username' => (string)$cfg['username'],
    'password' => (string)$cfg['password'],
    'brandCode' => (string)$cfg['brand_code'],
  ]);
  $url = $url . (str_contains($url, '?') ? '&' : '?') . $query;

  $http = iys_http_post_json($url, $jsonBody, (int)$cfg['timeout']);
  $httpCode = (int)($http['http_code'] ?? 0);
  $responseBody = (string)($http['body'] ?? '');
  $requestError = (string)($http['error'] ?? '');

  $ok = iys_is_success_response($httpCode, $responseBody, $requestError);

  return [
    'ok' => $ok,
    'skipped' => false,
    'http_code' => $httpCode,
    'response_body' => $responseBody,
    'error' => $ok ? '' : ($requestError !== '' ? $requestError : trim($responseBody)),
    'request_payload' => $payload,
    'request_endpoint' => (string)$cfg['endpoint'],
    'remote_status' => $remoteStatus,
    'channel_type' => $channelType,
  ];
}

function iys_sync_phone(PDO $pdo, string $phoneRaw, string $localStatus = 'onayli', array $opts = []): array
{
  iys_ensure_tables($pdo);

  $phoneRaw = trim($phoneRaw);
  $phoneE164 = iys_normalize_phone($phoneRaw);
  $localStatus = strtolower(trim($localStatus));

  $source = trim((string)($opts['source'] ?? 'manual'));
  $eventRef = trim((string)($opts['event_ref'] ?? ''));
  $consentDate = trim((string)($opts['consent_date'] ?? ''));
  $force = !empty($opts['force']);

  if ($phoneE164 === '' || ($localStatus !== 'onayli' && $localStatus !== 'onaysiz')) {
    return [
      'ok' => false,
      'skipped' => false,
      'error' => $phoneE164 === '' ? 'invalid_phone' : 'invalid_local_status',
      'phone_e164' => $phoneE164,
      'status' => $localStatus,
    ];
  }

  if (!$force) {
    $st = $pdo->prepare("SELECT last_status FROM iys_sync_state WHERE phone_e164 = ? LIMIT 1");
    $st->execute([$phoneE164]);
    $existing = $st->fetch();
    if ($existing && (string)($existing['last_status'] ?? '') === $localStatus) {
      iys_insert_log($pdo, [
        'phone_raw' => $phoneRaw,
        'phone_e164' => $phoneE164,
        'local_status' => $localStatus,
        'remote_status' => $localStatus === 'onayli' ? 'ONAY' : 'RET',
        'channel_type' => strtoupper((string)($opts['channel_type'] ?? 'MESAJ')),
        'source' => $source !== '' ? $source : 'manual',
        'event_ref' => $eventRef !== '' ? $eventRef : null,
        'request_json' => null,
        'response_text' => 'skipped_same_status',
        'http_code' => null,
        'success' => 1,
        'error' => 'skipped_same_status',
      ]);

      return [
        'ok' => true,
        'skipped' => true,
        'error' => '',
        'phone_e164' => $phoneE164,
        'status' => $localStatus,
        'reason' => 'already_synced_same_status',
      ];
    }
  }

  $overrides = [];
  foreach (['channel_type', 'consent_source', 'recipient_type'] as $k) {
    if (isset($opts[$k])) {
      $overrides[$k] = (string)$opts[$k];
    }
  }
  if (isset($opts['config']) && is_array($opts['config'])) {
    $overrides = array_merge($overrides, $opts['config']);
  }

  $send = iys_send_single($phoneE164, $localStatus, $consentDate, $overrides);

  $requestJson = null;
  if (isset($send['request_payload']) && is_array($send['request_payload'])) {
    $requestJson = json_encode($send['request_payload'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if (!is_string($requestJson)) $requestJson = null;
  }

  iys_insert_log($pdo, [
    'phone_raw' => $phoneRaw,
    'phone_e164' => $phoneE164,
    'local_status' => $localStatus,
    'remote_status' => (string)($send['remote_status'] ?? ''),
    'channel_type' => (string)($send['channel_type'] ?? ($overrides['channel_type'] ?? 'MESAJ')),
    'source' => $source !== '' ? $source : 'manual',
    'event_ref' => $eventRef !== '' ? $eventRef : null,
    'request_json' => $requestJson,
    'response_text' => (string)($send['response_body'] ?? ''),
    'http_code' => (int)($send['http_code'] ?? 0),
    'success' => !empty($send['ok']) ? 1 : 0,
    'error' => (string)($send['error'] ?? ''),
  ]);

  if (!empty($send['ok'])) {
    $stUpsert = $pdo->prepare("
      INSERT INTO iys_sync_state
        (phone_e164, last_status, last_channel_type, last_synced_at, last_http_code, last_response)
      VALUES (?, ?, ?, NOW(), ?, ?)
      ON DUPLICATE KEY UPDATE
        last_status = VALUES(last_status),
        last_channel_type = VALUES(last_channel_type),
        last_synced_at = VALUES(last_synced_at),
        last_http_code = VALUES(last_http_code),
        last_response = VALUES(last_response)
    ");
    $stUpsert->execute([
      $phoneE164,
      $localStatus,
      (string)($send['channel_type'] ?? 'MESAJ'),
      (int)($send['http_code'] ?? 0),
      (string)($send['response_body'] ?? ''),
    ]);
  }

  return [
    'ok' => !empty($send['ok']),
    'skipped' => !empty($send['skipped']),
    'error' => (string)($send['error'] ?? ''),
    'phone_e164' => $phoneE164,
    'status' => $localStatus,
    'http_code' => (int)($send['http_code'] ?? 0),
    'response_body' => (string)($send['response_body'] ?? ''),
  ];
}

function iys_insert_log(PDO $pdo, array $log): void
{
  $st = $pdo->prepare("
    INSERT INTO iys_sync_logs
      (phone_raw, phone_e164, local_status, remote_status, channel_type, source, event_ref, request_json, response_text, http_code, success, error)
    VALUES
      (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  ");
  $st->execute([
    (string)($log['phone_raw'] ?? ''),
    (string)($log['phone_e164'] ?? ''),
    (string)($log['local_status'] ?? ''),
    (string)($log['remote_status'] ?? ''),
    strtoupper((string)($log['channel_type'] ?? 'MESAJ')),
    (string)($log['source'] ?? 'manual'),
    $log['event_ref'] ?? null,
    $log['request_json'] ?? null,
    $log['response_text'] ?? null,
    isset($log['http_code']) ? (int)$log['http_code'] : null,
    !empty($log['success']) ? 1 : 0,
    (isset($log['error']) && (string)$log['error'] !== '') ? (string)$log['error'] : null,
  ]);
}

function iys_is_success_response(int $httpCode, string $body, string $requestError = ''): bool
{
  if ($requestError !== '') return false;
  if ($httpCode < 200 || $httpCode >= 300) return false;

  $trimmed = trim($body);
  if ($trimmed === '') return true;

  $lower = strtolower($trimmed);
  if (str_contains($lower, 'error')) return false;
  if (str_contains($lower, 'hata')) return false;
  if (str_contains($lower, 'no auth')) return false;
  if (str_contains($lower, 'unauthorized')) return false;
  if (str_contains($lower, 'forbidden')) return false;
  if (str_contains($lower, 'invalid')) return false;
  if (str_contains($lower, 'fail')) return false;

  return true;
}

function iys_http_post_json(string $url, string $jsonBody, int $timeout): array
{
  $headers = [
    'Content-Type: application/json; charset=utf-8',
    'Accept: application/json',
  ];

  if (function_exists('curl_init')) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonBody);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $body = curl_exec($ch);
    $err = curl_error($ch);
    $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return [
      'http_code' => $httpCode,
      'body' => is_string($body) ? $body : '',
      'error' => $err ?: '',
    ];
  }

  $ctx = stream_context_create([
    'http' => [
      'method' => 'POST',
      'header' => implode("\r\n", $headers) . "\r\n",
      'content' => $jsonBody,
      'timeout' => $timeout,
      'ignore_errors' => true,
    ],
  ]);

  $body = @file_get_contents($url, false, $ctx);
  $httpCode = 0;

  if (isset($http_response_header) && is_array($http_response_header)) {
    foreach ($http_response_header as $line) {
      if (preg_match('/^HTTP\/\S+\s+(\d{3})/i', (string)$line, $m)) {
        $httpCode = (int)($m[1] ?? 0);
        break;
      }
    }
  }

  $err = '';
  if ($body === false) {
    $last = error_get_last();
    $err = (string)($last['message'] ?? 'request_failed');
    $body = '';
  }

  return [
    'http_code' => $httpCode,
    'body' => (string)$body,
    'error' => $err,
  ];
}
