import { request } from '../api/client';

// The IPTV access-token endpoint (`GET /api/v1/auth/iptv-token`) lives on the [IgnoreApi] auth surface, so
// like the rest of `auth.ts` its DTO is hand-written here rather than sourced from `./generated/v1`.
// Wire fields are camelCase to match the server record `IptvTokenResponse(string Token, DateTimeOffset
// ExpiresAt)`.
export interface IptvToken {
  token: string;
  expiresAt: string;
}

interface CachedToken {
  token: string;
  expiresAtMs: number;
}

// Refresh a little before expiry so an in-flight play doesn't begin with an about-to-expire token (which
// would stall mid-stream). Well under the 60-minute default lifetime.
const REFRESH_SKEW_MS = 120_000;

let cached: CachedToken | null = null;
// Once the server answers 204 (IPTV JWT auth is off), it cannot turn on without a server restart — remember
// it so we don't re-hit the endpoint on every play. Reset via resetIptvTokenCache (used by tests).
let jwtDisabled = false;

export function resetIptvTokenCache(): void {
  cached = null;
  jwtDisabled = false;
}

/**
 * Fetch a short-lived `/iptv/*` access token for the browser (#552), or `null` when IPTV JWT auth is
 * disabled (the endpoint answers 204 and `/iptv/*` is open — nothing to append). Cached in memory until
 * shortly before expiry so repeated plays reuse one token.
 */
export async function getIptvToken(): Promise<string | null> {
  if (jwtDisabled) {
    return null;
  }

  if (cached && cached.expiresAtMs - Date.now() > REFRESH_SKEW_MS) {
    return cached.token;
  }

  const result = await request<IptvToken | undefined>('/api/v1/auth/iptv-token');
  if (!result) {
    // 204 No Content: IPTV JWT auth is off, so `/iptv/*` needs no token.
    jwtDisabled = true;
    cached = null;
    return null;
  }

  cached = { token: result.token, expiresAtMs: Date.parse(result.expiresAt) };
  return cached.token;
}

/**
 * Resolve a `/iptv/*` URL to one the browser can actually fetch under a JWT-enabled deployment, appending
 * `?access_token=`/`&access_token=` when a token is required. A no-op when JWT auth is disabled. Only the
 * top-level manifest URL needs this: the multi-variant playlist propagates the token to its variant, and
 * HLS segments are served by static-file middleware outside the JWT filter.
 */
export async function withIptvToken(url: string): Promise<string> {
  const token = await getIptvToken();
  if (!token) {
    return url;
  }

  const separator = url.includes('?') ? '&' : '?';
  return `${url}${separator}access_token=${encodeURIComponent(token)}`;
}
