import 'dart:convert';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:minstrel/api/endpoints/library.dart';

/// Stub adapter that returns a fixed JSON response for any request. The
/// body argument can be either a Map or a List (the artist-tracks endpoint
/// emits a top-level JSON array). Per-test wiring keeps the routing trivial.
class _StubAdapter implements HttpClientAdapter {
  _StubAdapter(this._body);
  final Object _body;

  @override
  Future<ResponseBody> fetch(
    RequestOptions options,
    Stream<Uint8List>? requestStream,
    Future<void>? cancelFuture,
  ) async {
    return ResponseBody.fromString(
      jsonEncode(_body),
      200,
      headers: const {
        Headers.contentTypeHeader: ['application/json'],
      },
    );
  }

  @override
  void close({bool force = false}) {}
}

Dio _dioWith(Object body) {
  final d = Dio(BaseOptions(baseUrl: 'http://example.test'));
  d.httpClientAdapter = _StubAdapter(body);
  return d;
}

void main() {
  group('LibraryApi', () {
    test('getAlbum parses album fields and tracks list', () async {
      final api = LibraryApi(_dioWith(<String, dynamic>{
        'id': 'al-1',
        'title': 'Geogaddi',
        'sort_title': 'geogaddi',
        'artist_id': 'art-1',
        'artist_name': 'Boards of Canada',
        'year': 2002,
        'track_count': 1,
        'duration_sec': 312,
        'cover_url': '/api/albums/al-1/cover',
        'tracks': [
          {
            'id': 't-1',
            'title': 'Music Is Math',
            'album_id': 'al-1',
            'album_title': 'Geogaddi',
            'artist_id': 'art-1',
            'artist_name': 'Boards of Canada',
            'duration_sec': 312,
            'track_number': 4,
            'stream_url': '/api/tracks/t-1/stream',
          },
        ],
      }));
      final r = await api.getAlbum('al-1');
      expect(r.album.id, 'al-1');
      expect(r.album.title, 'Geogaddi');
      expect(r.album.artistName, 'Boards of Canada');
      expect(r.album.year, 2002);
      expect(r.tracks, hasLength(1));
      expect(r.tracks.single.title, 'Music Is Math');
      expect(r.tracks.single.durationSec, 312);
      expect(r.tracks.single.trackNumber, 4);
    });

    test('getArtist parses ArtistDetail body as ArtistRef', () async {
      final api = LibraryApi(_dioWith(<String, dynamic>{
        'id': 'art-1',
        'name': 'Boards of Canada',
        'sort_name': 'boards of canada',
        'album_count': 5,
        'cover_url': '/api/albums/al-1/cover',
        'albums': const [],
      }));
      final a = await api.getArtist('art-1');
      expect(a.id, 'art-1');
      expect(a.name, 'Boards of Canada');
      expect(a.albumCount, 5);
    });

    test('getArtistAlbums extracts the albums array', () async {
      final api = LibraryApi(_dioWith(<String, dynamic>{
        'id': 'art-1',
        'name': 'Boards of Canada',
        'albums': [
          {
            'id': 'al-1',
            'title': 'Geogaddi',
            'artist_id': 'art-1',
            'artist_name': 'Boards of Canada',
          },
          {
            'id': 'al-2',
            'title': 'The Campfire Headphase',
            'artist_id': 'art-1',
            'artist_name': 'Boards of Canada',
          },
        ],
      }));
      final albums = await api.getArtistAlbums('art-1');
      expect(albums, hasLength(2));
      expect(albums.first.id, 'al-1');
      expect(albums.last.title, 'The Campfire Headphase');
    });

    test('getArtistTracks parses a top-level JSON array', () async {
      // Server emits a bare []TrackRef, NOT {"tracks": [...]}.
      final api = LibraryApi(_dioWith(<Map<String, dynamic>>[
        {
          'id': 't-1',
          'title': 'Music Is Math',
          'album_id': 'al-1',
          'album_title': 'Geogaddi',
          'artist_id': 'art-1',
          'artist_name': 'Boards of Canada',
          'duration_sec': 312,
        },
        {
          'id': 't-2',
          'title': 'Dawn Chorus',
          'album_id': 'al-1',
          'album_title': 'Geogaddi',
          'artist_id': 'art-1',
          'artist_name': 'Boards of Canada',
          'duration_sec': 168,
        },
      ]));
      final tracks = await api.getArtistTracks('art-1');
      expect(tracks, hasLength(2));
      expect(tracks.first.id, 't-1');
      expect(tracks.last.durationSec, 168);
    });

    test('getHome parses HomePayload sections', () async {
      final api = LibraryApi(_dioWith(<String, dynamic>{
        'recently_added_albums': [
          {
            'id': 'al-1',
            'title': 'Geogaddi',
            'artist_id': 'art-1',
            'artist_name': 'Boards of Canada',
          },
        ],
        'rediscover_albums': const [],
        'rediscover_artists': const [],
        'most_played_tracks': const [],
        'last_played_artists': [
          {'id': 'art-1', 'name': 'Boards of Canada'},
        ],
      }));
      final home = await api.getHome();
      expect(home.recentlyAddedAlbums.single.title, 'Geogaddi');
      expect(home.lastPlayedArtists.single.name, 'Boards of Canada');
      expect(home.rediscoverAlbums, isEmpty);
    });
  });
}
