import logging
import time

from django.core.management.base import BaseCommand

from music.listenbrainz import get_similar_recordings

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Fetch similar recordings from ListenBrainz for tracks with a musicbrainz_id"

    def add_arguments(self, parser):
        parser.add_argument(
            "--commit",
            action="store_true",
            help="Commit changes to the database",
        )
        parser.add_argument(
            "--batch-size",
            type=int,
            default=100,
            help="Number of tracks to process per batch (default: 100)",
        )
        parser.add_argument(
            "--track-id",
            type=str,
            default="",
            help="Only process the track with this musicbrainz_id",
        )
        parser.add_argument(
            "--overwrite",
            action="store_true",
            help="Re-fetch similar recordings even if already populated",
        )

    def handle(self, *args, **options):
        from music.models import Track

        commit = options["commit"]
        batch_size = options["batch_size"]
        track_id = options["track_id"]
        overwrite = options["overwrite"]

        if not commit:
            self.stdout.write(
                "Dry run — no changes will be saved. Use --commit to apply."
            )

        qs = Track.objects.exclude(musicbrainz_id__isnull=True).exclude(
            musicbrainz_id=""
        )

        if track_id:
            qs = qs.filter(musicbrainz_id=track_id)
            self.stdout.write(f"Filtering to track with musicbrainz_id: {track_id}")
        elif not overwrite:
            qs = qs.filter(similar_recordings__isnull=True)
        else:
            qs = qs.all()

        total = qs.count()
        if total == 0:
            self.stdout.write("No tracks to process.")
            return

        self.stdout.write(
            f"Found {total} tracks with musicbrainz_id"
            + (" (overwrite mode)" if overwrite else "")
            + (" (--track-id filter)" if track_id else "")
        )

        if not commit:
            self.stdout.write(
                "\nSkipping API lookups in dry-run mode. Use --commit to run against ListenBrainz."
            )
            return

        found_count = 0
        empty_count = 0
        error_count = 0
        track_ids = list(qs.values_list("pk", flat=True))
        i = 0

        for batch_num, offset in enumerate(
            range(0, len(track_ids), batch_size)
        ):
            batch_pks = track_ids[offset : offset + batch_size]
            for track in Track.objects.filter(pk__in=batch_pks).iterator():
                i += 1
                self.stdout.write(
                    f"  [{i}/{total}] Fetching similar recordings for {track}...",
                    ending="",
                )
                try:
                    similar = get_similar_recordings(track.musicbrainz_id)
                    if similar:
                        track.similar_recordings = similar
                        track.save(update_fields=["similar_recordings"])
                        self.stdout.write(
                            f" {len(similar)} similar recordings found"
                        )
                        found_count += 1
                    else:
                        track.similar_recordings = []
                        track.save(update_fields=["similar_recordings"])
                        self.stdout.write(" none found")
                        empty_count += 1
                except Exception as e:
                    self.stdout.write(f" error: {e}")
                    error_count += 1

            self.stdout.write(
                f"  Batch {batch_num + 1}: {offset + len(batch_pks)}/{total} processed, "
                f"found: {found_count}, empty: {empty_count}, errors: {error_count}"
            )
            time.sleep(1)

        self.stdout.write(
            f"\nResults (commit={commit}):\n"
            f"  Similar recordings found: {found_count}\n"
            f"  No similar recordings: {empty_count}\n"
            f"  Errors: {error_count}"
        )
