"""
Return an install to a blank site.

A new install is meant to start empty, and for a long time it did not: the
model defaults carried one agency's marketing copy, the bundled logo was that
agency's, and the fleet check-in pushed its name, logo and colours down on
every run. An install created before those were fixed is still wearing them,
and no amount of template work removes rows that are already in its database.

This clears the content and the borrowed branding. It never touches users,
tickets, enquiries, orders or settings such as SMTP and API keys.

    python manage.py blank_site                    show what is there
    python manage.py blank_site --apply --yes-i-am-sure <site name>

The site name has to be typed to apply, so this cannot be run against the
wrong install by pasting the wrong path.
"""

from django.apps import apps as django_apps
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

# Content that belongs to whoever the site is for. All of it goes.
CONTENT_APPS = ['pages', 'portfolio', 'insights', 'faq', 'testimonials', 'brands']

# Rows in those apps that are configuration rather than content, and stay.
KEEP_MODELS = {'SiteSettings'}

# Only what a site inherited from somewhere else. A logo pushed down by the
# fleet is borrowed, and founded_year defaulted to another company's year.
# Everything the owner typed themselves stays: the title suffix, the meta
# description, the favicon they uploaded, and every setting on the row.
BRAND_FIELDS = ['logo', 'founded_year']

# Panel colours are never touched. They are chrome, they are chosen once, and
# a content wipe that turns somebody's sidebar yellow is a wipe that did more
# than it was asked to.
TENANT_BRAND_FIELDS = []


class Command(BaseCommand):
    help = 'Clear content and borrowed branding so an install starts blank.'

    def add_arguments(self, parser):
        parser.add_argument('confirm_name', nargs='?', default='',
                            help='The tenant name, required with --apply.')
        parser.add_argument('--apply', action='store_true',
                            help='Actually delete. Without it, nothing changes.')
        parser.add_argument('--yes-i-am-sure', action='store_true',
                            dest='sure', help='Required with --apply.')
        parser.add_argument('--keep-media', action='store_true',
                            help='Leave uploaded files on disk, only clear the rows.')

    def handle(self, *args, **opts):
        from apps.tenants.models import Tenant

        tenants = list(Tenant.objects.all())
        if len(tenants) != 1:
            raise CommandError(
                'Expected exactly one tenant on this install, found %d. '
                'Refusing to guess which one to blank.' % len(tenants)
            )
        tenant = tenants[0]

        plan = []
        for label in CONTENT_APPS:
            try:
                cfg = django_apps.get_app_config(label)
            except LookupError:
                continue
            for model in cfg.get_models():
                if model.__name__ in KEEP_MODELS:
                    continue
                try:
                    n = model.objects.count()
                except Exception:
                    continue
                if n:
                    plan.append((label, model, n))

        self.stdout.write('  site   : %s' % tenant.name)
        self.stdout.write('  domain : %s' % (tenant.primary_domain or 'not set'))
        self.stdout.write('')
        if plan:
            for label, model, n in plan:
                self.stdout.write('  %-13s %-30s %4d rows' % (label, model.__name__, n))
        else:
            self.stdout.write('  no content rows, this install is already clear')

        site = self._site_settings(tenant)
        if site:
            self.stdout.write('')
            for f in BRAND_FIELDS:
                if not hasattr(site, f):
                    continue
                val = getattr(site, f)
                if val:
                    self.stdout.write('  branding      %-30s %s' % (f, str(val)[:48]))
        for f in TENANT_BRAND_FIELDS:
            val = getattr(tenant, f, '')
            if val:
                self.stdout.write('  panel colour  %-30s %s' % (f, val))

        if not opts['apply']:
            self.stdout.write('')
            self.stdout.write('  Nothing was changed. To clear all of the above:')
            self.stdout.write('    manage.py blank_site --apply --yes-i-am-sure "%s"' % tenant.name)
            return

        if not opts['sure'] or (opts['confirm_name'] or '').strip() != tenant.name:
            raise CommandError(
                'To apply, pass --yes-i-am-sure and the exact tenant name: "%s"'
                % tenant.name
            )

        removed = 0
        with transaction.atomic():
            for label, model, n in reversed(plan):
                try:
                    count = model.objects.all().delete()[0]
                except Exception as exc:
                    self.stderr.write('  could not clear %s: %s' % (model.__name__, exc))
                    continue
                removed += count
                self.stdout.write('  cleared %-30s %d' % (model.__name__, count))

            if site:
                touched = []
                for f in BRAND_FIELDS:
                    if not hasattr(site, f) or not getattr(site, f):
                        continue
                    field = site._meta.get_field(f)
                    if field.get_internal_type() in ('FileField', 'ImageField'):
                        if not opts['keep_media']:
                            try:
                                getattr(site, f).delete(save=False)
                            except Exception:
                                pass
                        setattr(site, f, None)
                    elif field.get_internal_type() == 'IntegerField':
                        setattr(site, f, None)
                    else:
                        setattr(site, f, '')
                    touched.append(f)
                if touched:
                    site.save()
                    self.stdout.write('  cleared branding on SiteSettings: %s' % ', '.join(touched))

            # Colours go back to the model default rather than to an empty
            # string. A blank hex renders a sidebar with no background at all,
            # which looks like a broken panel rather than a fresh one.
            touched = []
            for f in TENANT_BRAND_FIELDS:
                try:
                    fallback = tenant._meta.get_field(f).default
                except Exception:
                    continue
                if getattr(tenant, f, '') != fallback:
                    setattr(tenant, f, fallback)
                    touched.append(f)
            if touched:
                tenant.save(update_fields=touched)
                self.stdout.write('  panel colours reset to default: %s' % ', '.join(touched))

        self.stdout.write('')
        self.stdout.write('  done, %d rows removed. Restart the service.' % removed)

    def _site_settings(self, tenant):
        try:
            from apps.pages.models import SiteSettings
            return SiteSettings.load(tenant)
        except Exception:
            return None
