import re

from django.core.management.base import BaseCommand

from scrobbles.utils import tokenize_title_to_tags
from webpages.models import WebPage


def _clean(s: str) -> str:
    return re.sub(r"[^\x20-\x7e]", "", s)


class Command(BaseCommand):
    help = "Backfill auto tags on webpages from domain and title"

    def add_arguments(self, parser):
        parser.add_argument(
            "--commit",
            action="store_true",
            help="Actually add tags",
        )

    def handle(self, *args, **options):
        commit = options["commit"]

        webpages = WebPage.objects.all()
        total = webpages.count()
        updated_count = 0
        skipped_count = 0

        for i, webpage in enumerate(webpages.iterator(), start=1):
            new_tags = set()

            if webpage.domain:
                parts = webpage.domain.root.split(".")
                for part in parts:
                    part = part.strip().lower()
                    if part and part != "www":
                        new_tags.add(part)

            if webpage.title:
                title_tags = tokenize_title_to_tags(webpage.title)
                new_tags.update(title_tags)

            existing_tags = {
                t.name for t in webpage.tags.all()
            }
            tags_to_add = new_tags - existing_tags

            if tags_to_add:
                updated_count += 1
                if commit:
                    for tag in tags_to_add:
                        webpage.tags.add(tag)
                    self.stdout.write(
                        f"[{i}/{total}] Added tags to {_clean(str(webpage))}: "
                        f"{sorted(tags_to_add)}"
                    )
                else:
                    self.stdout.write(
                        f"[{i}/{total}] [DRY RUN] Would add tags to "
                        f"{_clean(str(webpage))}: {sorted(tags_to_add)}"
                    )
            else:
                skipped_count += 1

        self.stdout.write(f"\nDone. {updated_count} webpages to update, "
                          f"{skipped_count} already up to date.")
