import { Injectable, Logger } from '@nestjs/common';
import { createHmac } from 'crypto';
import type { MissionStateResponse } from '@fog-explorer/api-interfaces';

const PUBSUB_URL = 'https://api.twitch.tv/extensions/message';
const TOKEN_TTL_SECONDS = 60;

@Injectable()
export class TwitchPubSubService {
  private readonly logger = new Logger(TwitchPubSubService.name);

  async broadcast(
    channelId: string | null,
    state: NonNullable<MissionStateResponse>
  ): Promise<void> {
    if (!channelId) return;

    const clientId = process.env['TWITCH_CLIENT_ID'];
    const secret = process.env['TWITCH_EXTENSION_SECRET'];
    if (!clientId || !secret) return;

    const token = buildServerToken(clientId, secret);
    const payload = JSON.stringify({
      content_type: 'application/json',
      message: JSON.stringify(state),
      targets: ['broadcast'],
    });

    if (Buffer.byteLength(payload, 'utf8') > 5000) {
      this.logger.warn({ message: 'pubsub payload too large, skipping', channelId });
      return;
    }

    try {
      const res = await fetch(`${PUBSUB_URL}/${channelId}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Client-Id': clientId,
          'Content-Type': 'application/json',
        },
        body: payload,
      });

      if (!res.ok) {
        this.logger.warn({
          message: 'pubsub broadcast failed',
          channelId,
          status: res.status,
        });
      }
    } catch (err) {
      this.logger.error({ message: 'pubsub broadcast error', channelId, err });
    }
  }
}

function buildServerToken(clientId: string, secretB64: string): string {
  const secretBytes = Buffer.from(secretB64, 'base64');
  const exp = Math.floor(Date.now() / 1000) + TOKEN_TTL_SECONDS;

  const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
  const payload = Buffer.from(
    JSON.stringify({ exp, user_id: clientId, role: 'external' })
  ).toString('base64url');

  const sig = createHmac('sha256', secretBytes)
    .update(`${header}.${payload}`)
    .digest('base64url');

  return `${header}.${payload}.${sig}`;
}
