<?php
declare(strict_types=1);

function spotify_cfg(string $key, string $default = ''): string {
  $v = getenv($key);
  if ($v !== false && $v !== '') return $v;
  return $default;
}

function spotify_client_id(): string { return spotify_cfg('SPOTIFY_CLIENT_ID'); }
function spotify_client_secret(): string { return spotify_cfg('SPOTIFY_CLIENT_SECRET'); }
function spotify_redirect_uri(): string { return spotify_cfg('SPOTIFY_REDIRECT_URI'); }

function spotify_http_post(string $url, array $fields, array $headers = []): array {
  $ch = curl_init($url);
  curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($fields),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 12,
    CURLOPT_HTTPHEADER => array_merge([
      'Content-Type: application/x-www-form-urlencoded'
    ], $headers),
  ]);
  $raw = curl_exec($ch);
  $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
  $err = curl_error($ch);
  curl_close($ch);

  if ($raw === false) return ['ok'=>false,'code'=>$code,'error'=>$err ?: 'curl_error','data'=>null];
  $data = json_decode($raw, true);
  return ['ok'=>($code >= 200 && $code < 300),'code'=>$code,'error'=>$err ?: null,'data'=>$data];
}

function spotify_http_get(string $url, string $accessToken): array {
  $ch = curl_init($url);
  curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => [
      'Authorization: Bearer ' . $accessToken,
      'Accept: application/json',
    ],
  ]);
  $raw = curl_exec($ch);
  $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
  $err = curl_error($ch);
  curl_close($ch);

  if ($raw === false) return ['ok'=>false,'code'=>$code,'error'=>$err ?: 'curl_error','data'=>null];
  $data = ($raw !== '' ? json_decode($raw, true) : null);
  return ['ok'=>($code >= 200 && $code < 300),'code'=>$code,'error'=>$err ?: null,'data'=>$data];
}

function spotify_save_tokens(?string $refresh, ?string $access, int $expiresIn): void {
  $expiresAt = time() + max(0, $expiresIn) - 30; // safety margin
  $stmt = pdo()->prepare("
    UPDATE spotify_tokens
       SET refresh_token = COALESCE(?, refresh_token),
           access_token = ?,
           access_expires = ?,
           updated_at = ?
     WHERE id = 1
  ");
  $stmt->execute([$refresh, $access, $expiresAt, time()]);
}

function spotify_get_stored_row(): ?array {
  try {
    $row = pdo()->query("SELECT refresh_token, access_token, access_expires FROM spotify_tokens WHERE id=1")->fetch();
    return $row ?: null;
  } catch (Throwable $e) {
    return null;
  }
}

function spotify_exchange_code_for_tokens(string $code): bool {
  $cid = spotify_client_id();
  $sec = spotify_client_secret();
  $redir = spotify_redirect_uri();
  if ($cid === '' || $sec === '' || $redir === '') return false;

  $basic = base64_encode($cid . ':' . $sec);
  $res = spotify_http_post(
    'https://accounts.spotify.com/api/token',
    [
      'grant_type' => 'authorization_code',
      'code' => $code,
      'redirect_uri' => $redir,
    ],
    ['Authorization: Basic ' . $basic]
  );

  if (!$res['ok'] || !is_array($res['data'])) return false;

  $access = (string)($res['data']['access_token'] ?? '');
  $refresh = (string)($res['data']['refresh_token'] ?? '');
  $expires = (int)($res['data']['expires_in'] ?? 0);

  if ($access === '' || $refresh === '' || $expires <= 0) return false;
  spotify_save_tokens($refresh, $access, $expires);
  return true;
}

function spotify_refresh_access_token(): ?string {
  $row = spotify_get_stored_row();
  $refresh = (string)($row['refresh_token'] ?? '');
  if ($refresh === '') return null;

  $cid = spotify_client_id();
  $sec = spotify_client_secret();
  if ($cid === '' || $sec === '') return null;

  $basic = base64_encode($cid . ':' . $sec);
  $res = spotify_http_post(
    'https://accounts.spotify.com/api/token',
    [
      'grant_type' => 'refresh_token',
      'refresh_token' => $refresh,
    ],
    ['Authorization: Basic ' . $basic]
  );

  if (!$res['ok'] || !is_array($res['data'])) return null;

  $access = (string)($res['data']['access_token'] ?? '');
  $expires = (int)($res['data']['expires_in'] ?? 0);
  if ($access === '' || $expires <= 0) return null;

  // refresh token usually not returned here; keep existing one
  spotify_save_tokens(null, $access, $expires);
  return $access;
}

function spotify_get_access_token(): ?string {
  $row = spotify_get_stored_row();
  if (!$row) return null;

  $access = (string)($row['access_token'] ?? '');
  $exp = (int)($row['access_expires'] ?? 0);

  if ($access !== '' && $exp > time() + 30) return $access;
  return spotify_refresh_access_token();
}
