#!/usr/bin/env python3
"""
Finish the remaining 9 failed migrations.

The root cause: users.0022 tries to AlterField on 'defaultrolepermission' and
'userpermission' tables that don't exist yet (created in 0024). Since the SQL
parts (DROP INDEX IF EXISTS, DROP COLUMN IF EXISTS) are safe no-ops and the
AlterField operations only update Django's internal state, we fake 0022 then
run the rest normally.

Run on server: python finish_migrations.py
"""
import os
import sys
import subprocess
from datetime import datetime

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings_production')

try:
    from dotenv import load_dotenv
    load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env'), override=True)
except ImportError:
    pass

import django
django.setup()
from django.db import connection

py = sys.executable

def run(cmd, ignore_errors=False):
    print(f"\n>>> {cmd}")
    result = subprocess.run(cmd, shell=True, text=True, capture_output=True)
    out = (result.stdout + result.stderr).strip()
    if out:
        # Only print last 20 lines to keep output clean
        lines = out.splitlines()
        if len(lines) > 20:
            print(f"  ... ({len(lines)-20} lines omitted) ...")
            print('\n'.join(lines[-20:]))
        else:
            print(out)
    ok = result.returncode == 0
    print(f"  {'OK' if ok else 'FAILED'} (exit {result.returncode})")
    return ok

def is_applied(app, name):
    with connection.cursor() as c:
        c.execute(
            "SELECT COUNT(*) FROM django_migrations WHERE app=%s AND name=%s",
            [app, name]
        )
        return c.fetchone()[0] > 0

print(f"\n{'='*60}")
print(f"  Finish Migrations  {datetime.now():%Y-%m-%d %H:%M:%S}")
print(f"{'='*60}")

# ── Step 1: Fake users.0022 ───────────────────────────────────
# Its SQL ops (DROP IF EXISTS) are safe no-ops already applied.
# The AlterField ops fail because defaultrolepermission/userpermission
# don't exist yet — they're created in 0024. Faking is safe.
print("\n[1] Faking users.0022 (AlterField on tables not yet created)...")
if is_applied('users', '0022_remove_rolepermission_role_permis_role_056d99_idx_and_more'):
    print("  Already applied — skipping")
else:
    run(f"{py} manage.py migrate users 0022_remove_rolepermission_role_permis_role_056d99_idx_and_more --fake")

# ── Step 2: Run users.0023 and 0024 normally ─────────────────
print("\n[2] Running users.0023 and users.0024...")
for migration in [
    '0023_add_client_approval_fields',
    '0024_enhanced_permissions_models',
]:
    if is_applied('users', migration):
        print(f"  {migration} already applied — skipping")
    else:
        run(f"{py} manage.py migrate users {migration}")

# ── Step 3: Run remaining users migrations ────────────────────
print("\n[3] Running remaining users migrations...")
for migration in [
    '0003_seed_granular_permissions',
    '0004_enhanced_audit_system',
    '0005_add_role_template_rollback_point',
    '0006_remove_rolepermission_role_permis_role_056d99_idx_and_more',
]:
    if is_applied('users', migration):
        print(f"  {migration} already applied — skipping")
    else:
        ok = run(f"{py} manage.py migrate users {migration}")
        if not ok:
            print(f"  Faking {migration} due to conflict...")
            run(f"{py} manage.py migrate users {migration} --fake")

# ── Step 4: Run utils.0018 and 0019 ──────────────────────────
print("\n[4] Running utils.0018 and utils.0019...")
for migration in [
    '0018_add_portfolio_notification_fields',
    '0019_notificationrule_and_more',
]:
    if is_applied('utils', migration):
        print(f"  {migration} already applied — skipping")
    else:
        ok = run(f"{py} manage.py migrate utils {migration}")
        if not ok:
            print(f"  Faking {migration} due to conflict...")
            run(f"{py} manage.py migrate utils {migration} --fake")

# ── Step 5: Final migrate to catch anything left ──────────────
print("\n[5] Final migrate pass...")
run(f"{py} manage.py migrate", ignore_errors=True)

# ── Step 6: Verify ────────────────────────────────────────────
print("\n[6] Checking remaining unapplied migrations...")
result = subprocess.run(
    f"{py} manage.py showmigrations --plan",
    shell=True, text=True, capture_output=True
)
unapplied = [l.strip() for l in result.stdout.splitlines() if l.strip().startswith('[ ]')]
if unapplied:
    print(f"  {len(unapplied)} still unapplied:")
    for m in unapplied:
        print(f"    {m}")
else:
    print("  All migrations applied!")

print("\n[7] Verifying critical tables...")
critical = [
    'django_session', 'users', 'loans', 'utils_systemsetting',
    'utils_notification', 'role_permissions', 'cache_table',
    'notification_rules', 'notification_templates',
]
with connection.cursor() as c:
    c.execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE()")
    existing = {r[0].lower() for r in c.fetchall()}

all_ok = True
for table in critical:
    status = "OK     " if table.lower() in existing else "MISSING"
    if table.lower() not in existing:
        all_ok = False
    print(f"  {status}  {table}")

print(f"\n{'='*60}")
if all_ok and not unapplied:
    print("  ALL DONE — restart your app in cPanel.")
elif all_ok:
    print("  Tables OK. Some migrations still pending but app should work.")
    print("  Restart your app in cPanel.")
else:
    print("  Some issues remain — check output above.")
print(f"{'='*60}\n")
