// Discogs API client (read-only search).
//
// Auth is via a personal access token sent as the
// `Authorization: Discogs token=<TOKEN>` header (set through the http base).
// Discogs allows ~60 requests/minute for authenticated clients, enforced via the
// http base's per-host rate limit (minIntervalMs ~1100ms).
//
// Best-effort: with no token configured, or on any error, methods log a warning
// and return null rather than throwing, so enrichment never breaks the worker.

import { integrationsConfig, DiscogsConfig } from './config.js';
import { buildUserAgent, requestJson } from './http.js';

/** A normalised Discogs release match. */
export interface DiscogsRelease {
  discogsId: number;
  year: number | null;
  genres: string[];
  styles: string[];
  /** Cover image (full-size) URL, if any. */
  coverImage: string | null;
  /** Thumbnail URL, if any. */
  thumb: string | null;
}

// --- Raw Discogs response shapes (only the fields we read) -----------------

interface DiscogsSearchResult {
  id?: number;
  year?: string | number;
  genre?: string[];
  style?: string[];
  cover_image?: string;
  thumb?: string;
}

interface DiscogsSearchResponse {
  results?: DiscogsSearchResult[];
}

interface DiscogsArtistResponse {
  images?: { uri?: string; uri150?: string; type?: string }[];
}

export class DiscogsClient {
  private readonly cfg: DiscogsConfig;
  private readonly userAgent: string;
  private readonly enabled: boolean;

  constructor(cfg: DiscogsConfig = integrationsConfig.discogs) {
    this.cfg = cfg;
    this.userAgent = buildUserAgent(integrationsConfig.musicbrainz.contact);
    this.enabled = cfg.token.trim() !== '';
    if (!this.enabled) {
      console.warn(
        '[Discogs] DISCOGS_TOKEN not set; client disabled (methods return null).'
      );
    }
  }

  private async get<T>(path: string): Promise<T> {
    return requestJson<T>(`${this.cfg.baseUrl}${path}`, {
      userAgent: this.userAgent,
      minIntervalMs: this.cfg.minIntervalMs,
      headers: { Authorization: `Discogs token=${this.cfg.token}` },
    });
  }

  /**
   * Search the database for the best release match for artist/album and return
   * its id, year, genres/styles and cover image URLs, or null if no match (or
   * the client is disabled / errors).
   */
  async searchRelease(artist: string, album: string): Promise<DiscogsRelease | null> {
    if (!this.enabled) return null;
    if (artist.trim() === '' || album.trim() === '') return null;

    const qs = new URLSearchParams({
      type: 'release',
      artist,
      release_title: album,
    });
    const path = `/database/search?${qs.toString()}`;

    try {
      const data = await this.get<DiscogsSearchResponse>(path);
      const best = (data.results ?? [])[0];
      if (!best || typeof best.id !== 'number') return null;

      const year =
        best.year !== undefined && Number.isFinite(Number(best.year))
          ? Number(best.year)
          : null;

      return {
        discogsId: best.id,
        year,
        genres: best.genre ?? [],
        styles: best.style ?? [],
        coverImage: best.cover_image ?? null,
        thumb: best.thumb ?? null,
      };
    } catch (err) {
      console.warn('[Discogs] searchRelease failed:', (err as Error).message);
      return null;
    }
  }

  /**
   * Fetch artist images from Discogs using MusicBrainz ID for exact match.
   * Does NOT fall back to name-based search (too error-prone for common names).
   * Returns null if no MBID provided or no match found.
   */
  async getArtistImageUrl(_artistName: string, artistMbid?: string): Promise<string | null> {
    if (!this.enabled || !artistMbid?.trim()) return null;

    try {
      const mbPath = `/artists/${encodeURIComponent(artistMbid)}`;
      const data = await this.get<DiscogsArtistResponse>(mbPath);
      const images = data.images ?? [];
      
      // Prefer primary image, then first available
      const primary = images.find((img) => img.type === 'primary') ?? images[0];
      return primary?.uri150 ?? primary?.uri ?? null;
    } catch (err) {
      console.warn('[Discogs] getArtistImageUrl failed:', (err as Error).message);
      return null;
    }
  }
}
