#!/bin/bash
set -e

# ============================================================
# deploy_gl_fix.sh – Production deployment for GL fix
# Usage: bash deploy_gl_fix.sh [--dry-run] [--no-git] [--no-static]
# ============================================================

DRY_RUN=0
NO_GIT=0
NO_STATIC=0

for arg in "$@"; do
  case "$arg" in
    --dry-run)   DRY_RUN=1 ;;
    --no-git)    NO_GIT=1 ;;
    --no-static) NO_STATIC=1 ;;
  esac
done

info()  { echo "[INFO] $*"; }
ok()    { echo "[OK]   $*"; }
warn()  { echo "[WARN] $*"; }
fail()  { echo "[FAIL] $*"; exit 1; }

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"
info "Working directory: $SCRIPT_DIR"

# ------------------------------------------------------------------ #
# Auto-detect Python interpreter
# ------------------------------------------------------------------ #
PYTHON=""
for candidate in python3 python; do
  if command -v "$candidate" >/dev/null 2>&1; then
    PYTHON="$candidate"
    break
  fi
done

if [ -z "$PYTHON" ]; then
  for pattern in "$HOME/virtualenv/*/bin/python" "$HOME/.virtualenvs/*/bin/python"; do
    for p in $pattern; do
      if [ -x "$p" ]; then
        PYTHON="$p"
        break 2
      fi
    done
  done
fi

if [ -z "$PYTHON" ]; then
  fail "No Python interpreter found. Add python3 to PATH or create a virtualenv."
fi
info "Using Python: $PYTHON"

# ------------------------------------------------------------------ #
# Step 1 – Git pull
# ------------------------------------------------------------------ #
if [ "$NO_GIT" -eq 0 ]; then
  info "Step 1 – Git pull..."
  git pull || warn "git pull failed – continuing with current code."
  ok "Step 1 done."
else
  info "Step 1 – Skipped (--no-git)."
fi

# ------------------------------------------------------------------ #
# Step 2 – Install dependencies
# ------------------------------------------------------------------ #
info "Step 2 – pip install..."
$PYTHON -m pip install -q -r requirements.txt
ok "Step 2 done."

# ------------------------------------------------------------------ #
# Step 3 – Migrate
# ------------------------------------------------------------------ #
info "Step 3 – migrate..."
$PYTHON manage.py migrate --run-syncdb
ok "Step 3 done."

# ------------------------------------------------------------------ #
# Step 4 – Ensure required accounts exist
# ------------------------------------------------------------------ #
info "Step 4 – Ensuring required accounts exist..."

cat > /tmp/_deploy_accounts.py << 'PYEOF'
import django, os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()
from accounting.models import Account

ACCOUNTS = [
    ('1010', 'Cash and Bank Balances',           'asset'),
    ('1020', 'Loan Portfolio – Performing',       'asset'),
    ('4010', 'Interest Income – Loans',           'income'),
    ('401002', 'Fee Income – Loans',              'income'),
    ('3010', 'Share Capital',                     'equity'),
    ('3020', 'Retained Earnings',                 'equity'),
    ('2010', 'Accounts Payable',                  'liability'),
    ('501001', 'Salaries and Wages',              'expense'),
    ('501007', 'Administrative Expenses',         'expense'),
]

for code, name, atype in ACCOUNTS:
    obj, created = Account.objects.get_or_create(
        code=code,
        defaults={'name': name, 'account_type': atype, 'is_active': True},
    )
    status = 'CREATED' if created else 'EXISTS '
    print(f'  {status} {code} – {obj.name}')
PYEOF

$PYTHON /tmp/_deploy_accounts.py
rm -f /tmp/_deploy_accounts.py
ok "Step 4 done."

# ------------------------------------------------------------------ #
# Step 5 – Ensure fiscal periods
# ------------------------------------------------------------------ #
info "Step 5 – Ensuring fiscal periods..."

cat > /tmp/_deploy_periods.py << 'PYEOF'
import django, os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

import datetime
from dateutil.relativedelta import relativedelta
from django.db.models import Min
from accounting.models import FiscalPeriod
from loans.models import Loan, Repayment

# Determine date range
earliest_loan = Loan.objects.filter(
    disbursement_date__isnull=False, is_deleted=False
).aggregate(d=Min('disbursement_date'))['d']

earliest_rep = Repayment.objects.aggregate(d=Min('payment_date'))['d']

candidates = [d for d in [earliest_loan, earliest_rep] if d is not None]
if candidates:
    earliest_dt = min(candidates)
    if hasattr(earliest_dt, 'date'):
        earliest_dt = earliest_dt.date()
    start_year = earliest_dt.year
else:
    start_year = datetime.date.today().year

end_year = datetime.date.today().year + 2
created_count = 0

for year in range(start_year, end_year + 1):
    # Annual period
    annual_start = datetime.date(year, 1, 1)
    annual_end   = datetime.date(year, 12, 31)
    _, c = FiscalPeriod.objects.get_or_create(
        period_type='annual',
        start_date=annual_start,
        end_date=annual_end,
        defaults={'name': str(year), 'status': 'open'},
    )
    if c:
        created_count += 1

    # Monthly periods
    for month in range(1, 13):
        ms = datetime.date(year, month, 1)
        me = (ms + relativedelta(months=1)) - datetime.timedelta(days=1)
        _, c = FiscalPeriod.objects.get_or_create(
            period_type='monthly',
            start_date=ms,
            end_date=me,
            defaults={'name': ms.strftime('%B %Y'), 'status': 'open'},
        )
        if c:
            created_count += 1

# Collect all loan/repayment dates
loan_dates = list(
    Loan.objects.filter(disbursement_date__isnull=False, is_deleted=False)
    .values_list('disbursement_date', flat=True)
)
rep_dates = list(Repayment.objects.values_list('payment_date', flat=True))
all_dates = set()
for d in loan_dates + rep_dates:
    if hasattr(d, 'date'):
        d = d.date()
    all_dates.add(d)

reopened = 0
for d in all_dates:
    closed = FiscalPeriod.objects.filter(
        start_date__lte=d, end_date__gte=d, status='closed'
    )
    for p in closed:
        p.status = 'open'
        p.save(update_fields=['status'])
        reopened += 1

print('  Created ' + str(created_count) + ' fiscal period(s).')
print('  Reopened ' + str(reopened) + ' closed period(s) covering transaction dates.')
PYEOF

$PYTHON /tmp/_deploy_periods.py
rm -f /tmp/_deploy_periods.py
ok "Step 5 done."

# ------------------------------------------------------------------ #
# Step 6 – Backfill GL from loans
# ------------------------------------------------------------------ #
info "Step 6 – Backfill GL from loans..."
if [ "$DRY_RUN" -eq 1 ]; then
  $PYTHON manage.py backfill_gl_from_loans --dry-run
else
  $PYTHON manage.py backfill_gl_from_loans
fi
ok "Step 6 done."

# ------------------------------------------------------------------ #
# Step 7 – Data integrity check
# ------------------------------------------------------------------ #
info "Step 7 – Data integrity check..."
$PYTHON manage.py data_integrity_check
ok "Step 7 done."

# ------------------------------------------------------------------ #
# Step 8 – Clear cache and AccountBalance
# ------------------------------------------------------------------ #
info "Step 8 – Clearing cache..."

cat > /tmp/_deploy_cache.py << 'PYEOF'
import django, os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()
from django.core.cache import cache
cache.clear()
print('  Django cache cleared.')
try:
    from accounting.models import AccountBalance
    n = AccountBalance.objects.all().delete()
    print('  AccountBalance rows deleted: ' + str(n[0]))
except Exception as e:
    print('  AccountBalance not found or already empty: ' + str(e))
PYEOF

$PYTHON /tmp/_deploy_cache.py
rm -f /tmp/_deploy_cache.py
ok "Step 8 done."

# ------------------------------------------------------------------ #
# Step 9 – Collect static files
# ------------------------------------------------------------------ #
if [ "$NO_STATIC" -eq 0 ]; then
  info "Step 9 – collectstatic..."
  $PYTHON manage.py collectstatic --noinput -v 0
  ok "Step 9 done."
else
  info "Step 9 – Skipped (--no-static)."
fi

# ------------------------------------------------------------------ #
# Step 10 – Restart application server
# ------------------------------------------------------------------ #
info "Step 10 – Restarting application..."
if [ -f "passenger_wsgi.py" ]; then
  touch passenger_wsgi.py
  ok "Touched passenger_wsgi.py."
elif [ -d "tmp" ]; then
  touch tmp/restart.txt
  ok "Touched tmp/restart.txt."
else
  mkdir -p tmp && touch tmp/restart.txt
  ok "Created tmp/restart.txt."
fi
ok "Step 10 done."

# ------------------------------------------------------------------ #
# Final summary
# ------------------------------------------------------------------ #
info "Generating deployment summary..."

cat > /tmp/_deploy_summary.py << 'PYEOF'
import django, os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

from decimal import Decimal
from accounting.models import Account, GeneralLedger, JournalEntry, FiscalPeriod

gl_count = GeneralLedger.objects.count()
je_count = JournalEntry.objects.filter(status='posted').count()
open_periods = FiscalPeriod.objects.filter(status='open').count()

def bal(code):
    try:
        acc = Account.objects.get(code=code)
        last = GeneralLedger.objects.filter(account=acc).order_by('-transaction_date', '-posted_at', '-id').first()
        return last.balance if last else Decimal('0.00')
    except Exception:
        return Decimal('0.00')

b1010 = bal('1010')
b1020 = bal('1020')
b3010 = bal('3010')
b4010 = bal('4010')

total_assets = sum(
    (gl.balance or Decimal('0'))
    for acc in Account.objects.filter(account_type='asset')
    for gl in [GeneralLedger.objects.filter(account=acc).order_by('-transaction_date', '-posted_at', '-id').first()]
    if gl
)
total_liabilities = sum(
    (gl.balance or Decimal('0'))
    for acc in Account.objects.filter(account_type='liability')
    for gl in [GeneralLedger.objects.filter(account=acc).order_by('-transaction_date', '-posted_at', '-id').first()]
    if gl
)
total_equity = sum(
    (gl.balance or Decimal('0'))
    for acc in Account.objects.filter(account_type='equity')
    for gl in [GeneralLedger.objects.filter(account=acc).order_by('-transaction_date', '-posted_at', '-id').first()]
    if gl
)

balanced = 'YES' if abs(total_assets - (total_liabilities + total_equity)) < Decimal('0.01') else 'NO'

print('')
print('=' * 60)
print('DEPLOYMENT SUMMARY')
print('=' * 60)
print('GL entries:          ' + str(gl_count))
print('Posted JEs:          ' + str(je_count))
print('Open fiscal periods: ' + str(open_periods))
print('')
print('Account Balances:')
print('  1010 Cash:            KES ' + str(b1010))
print('  1020 Loan Portfolio:  KES ' + str(b1020))
print('  3010 Share Capital:   KES ' + str(b3010))
print('  4010 Interest Income: KES ' + str(b4010))
print('')
print('Total Assets:      KES ' + str(total_assets))
print('Total Liabilities: KES ' + str(total_liabilities))
print('Total Equity:      KES ' + str(total_equity))
print('SFP Balanced:      ' + balanced)
print('=' * 60)
PYEOF

$PYTHON /tmp/_deploy_summary.py
rm -f /tmp/_deploy_summary.py

ok "Deployment complete."
