import glob
import logging
import os
import re
import shutil
import subprocess
from datetime import datetime, timedelta
from pathlib import Path

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Count, Q, Sum
from django.db.models.functions import TruncMonth
from django.http import FileResponse
from django.shortcuts import redirect, render
from django.utils import timezone
from django.views.decorators.http import require_POST

from accounts.utils import sanitize_workbook, staff_required
from activities.models import Activity
from facilities.models import Facility
from inventory.models import Asset, AssetCategory
from maintenance.models import Maintenance

logger = logging.getLogger('it_management')


def _status_counts(queryset, field='status'):
    """شمارش گروهی با یک کوئری به جای چندین count()."""
    return {
        row[field]: row['total']
        for row in queryset.values(field).annotate(total=Count('id'))
    }


@login_required(login_url='login')
def dashboard_home(request):
    today = timezone.localdate()

    # ---------- تجهیزات ----------
    asset_counts = _status_counts(Asset.objects.all())
    asset_total = sum(asset_counts.values())
    asset_quantity = Asset.objects.aggregate(q=Sum('quantity'))['q'] or 0

    asset_order = ['ACTIVE', 'DAMAGED', 'UNDER_REPAIR', 'STORED', 'LOST', 'DISPOSED']
    asset_labels = dict(Asset.STATUS_CHOICES)

    # ---------- تعمیرات ----------
    maint_counts = _status_counts(Maintenance.objects.all())
    maint_total = sum(maint_counts.values())
    maint_order = ['PENDING', 'IN_PROGRESS', 'SENT_OUT', 'COMPLETED', 'NOT_REPAIRABLE']
    maint_labels = dict(Maintenance.STATUS_CHOICES)

    maint_cost = Maintenance.objects.aggregate(c=Sum('cost'))['c'] or 0
    overdue_maintenance = Maintenance.objects.filter(
        status__in=['PENDING', 'IN_PROGRESS', 'SENT_OUT'],
        report_date__lte=today - timedelta(days=14),
    ).count()

    # ---------- گارانتی ----------
    warranty_soon_qs = Asset.objects.filter(
        warranty_expiry__gte=today,
        warranty_expiry__lte=today + timedelta(days=60),
    ).exclude(status__in=['DISPOSED', 'LOST']).select_related(
        'category', 'location'
    ).order_by('warranty_expiry')
    warranty_soon = list(warranty_soon_qs[:5])
    warranty_soon_count = warranty_soon_qs.count()
    warranty_expired_count = Asset.objects.filter(
        warranty_expiry__lt=today
    ).exclude(status__in=['DISPOSED', 'LOST']).count()

    # ---------- فعالیت‌ها ----------
    activity_counts = _status_counts(Activity.objects.all())
    activity_total = sum(activity_counts.values())
    month_start = today.replace(day=1)
    activities_this_month = Activity.objects.filter(date__gte=month_start).count()

    # روند ۶ ماه اخیر
    six_months_ago = (month_start - timedelta(days=150)).replace(day=1)
    trend_rows = (
        Activity.objects.filter(date__gte=six_months_ago)
        .annotate(m=TruncMonth('date'))
        .values('m').annotate(total=Count('id')).order_by('m')
    )
    trend_map = {r['m']: r['total'] for r in trend_rows}
    trend_labels, trend_data = [], []
    cursor = six_months_ago
    for _ in range(6):
        trend_labels.append(cursor.strftime('%Y-%m'))
        trend_data.append(trend_map.get(cursor, 0))
        cursor = (cursor + timedelta(days=32)).replace(day=1)

    # ---------- دسته‌ها و مکان‌ها ----------
    category_rows = (
        AssetCategory.objects.annotate(total=Count('assets'))
        .filter(total__gt=0).order_by('-total')[:6]
    )
    location_rows = (
        Facility.objects.annotate(total=Count('assets'))
        .filter(total__gt=0).order_by('-total')[:5]
    )

    active_assets = asset_counts.get('ACTIVE', 0)
    health_percent = round(active_assets * 100 / asset_total) if asset_total else 0
    completed_maint = maint_counts.get('COMPLETED', 0)
    repair_rate = round(completed_maint * 100 / maint_total) if maint_total else 0

    context = {
        # آمار عمومی
        'facility_count': Facility.objects.count(),
        'asset_count': asset_total,
        'asset_quantity': asset_quantity,
        'activity_count': activity_total,
        'maintenance_count': maint_total,

        # وضعیت تجهیزات (سازگار با قالب‌های قبلی)
        'active_assets': active_assets,
        'damaged_assets': asset_counts.get('DAMAGED', 0),
        'repair_assets': asset_counts.get('UNDER_REPAIR', 0),
        'lost_assets': asset_counts.get('LOST', 0),
        'stored_assets': asset_counts.get('STORED', 0),
        'disposed_assets': asset_counts.get('DISPOSED', 0),

        # وضعیت تعمیرات
        'maintenance_pending': maint_counts.get('PENDING', 0),
        'maintenance_in_progress': maint_counts.get('IN_PROGRESS', 0),
        'maintenance_sent_out': maint_counts.get('SENT_OUT', 0),
        'maintenance_completed': completed_maint,
        'maintenance_not_repairable': maint_counts.get('NOT_REPAIRABLE', 0),
        'maintenance_open': (
            maint_counts.get('PENDING', 0)
            + maint_counts.get('IN_PROGRESS', 0)
            + maint_counts.get('SENT_OUT', 0)
        ),
        'maintenance_cost': maint_cost,
        'overdue_maintenance': overdue_maintenance,

        # شاخص‌ها
        'health_percent': health_percent,
        'repair_rate': repair_rate,
        'activities_this_month': activities_this_month,
        'activities_pending': (
            activity_counts.get('PENDING', 0) + activity_counts.get('IN_PROGRESS', 0)
        ),

        # گارانتی
        'warranty_soon': warranty_soon,
        'warranty_soon_count': warranty_soon_count,
        'warranty_expired_count': warranty_expired_count,

        # داده‌ی نمودارها (با json_script در قالب)
        'charts': {
            'assets': {
                'labels': [str(asset_labels[k]) for k in asset_order],
                'data': [asset_counts.get(k, 0) for k in asset_order],
            },
            'maintenance': {
                'labels': [str(maint_labels[k]) for k in maint_order],
                'data': [maint_counts.get(k, 0) for k in maint_order],
            },
            'categories': {
                'labels': [c.name for c in category_rows],
                'data': [c.total for c in category_rows],
            },
            'trend': {'labels': trend_labels, 'data': trend_data},
            'locations': {
                'labels': [f.name for f in location_rows],
                'data': [f.total for f in location_rows],
            },
        },

        # جدول‌ها
        'attention_assets': Asset.objects.filter(
            status__in=['DAMAGED', 'UNDER_REPAIR', 'LOST', 'DISPOSED']
        ).select_related('category', 'location').order_by('status', 'asset_code')[:8],

        'pending_maintenance': Maintenance.objects.filter(
            status__in=['PENDING', 'IN_PROGRESS', 'SENT_OUT']
        ).select_related(
            'asset', 'asset__category', 'asset__location'
        ).order_by('report_date', '-created_at')[:8],

        'latest_activities': Activity.objects.select_related(
            'activity_type', 'location', 'asset'
        ).order_by('-date', '-created_at')[:6],

        'today': today,
    }

    return render(request, 'dashboard/home.html', context)


@login_required(login_url='login')
def reports_home(request):

    # آمار مکان‌ها
    total_facilities = Facility.objects.count()
    active_facilities = Facility.objects.filter(status='ACTIVE').count()

    # آمار تجهیزات
    total_assets = Asset.objects.count()
    active_assets = Asset.objects.filter(status='ACTIVE').count()
    damaged_assets = Asset.objects.filter(status='DAMAGED').count()
    under_repair_assets = Asset.objects.filter(status='UNDER_REPAIR').count()
    
    stored_assets = Asset.objects.filter(status='STORED').count()
    lost_assets = Asset.objects.filter(status='LOST').count()
    disposed_assets = Asset.objects.filter(status='DISPOSED').count()

    # آمار فعالیت‌های تخنیکی
    total_activities = Activity.objects.count()
    completed_activities = Activity.objects.filter(status='COMPLETED').count()
    pending_activities = Activity.objects.filter(status='PENDING').count()

    # آمار تعمیرات
    total_maintenance = Maintenance.objects.count()
    completed_maintenance = Maintenance.objects.filter(status='COMPLETED').count()
    pending_maintenance = Maintenance.objects.filter(status='PENDING').count()
    in_progress_maintenance = Maintenance.objects.filter(status='IN_PROGRESS').count()

    context = {
        'total_facilities': total_facilities,
        'active_facilities': active_facilities,

        'total_assets': total_assets,
        'active_assets': active_assets,
        'damaged_assets': damaged_assets,
        'under_repair_assets': under_repair_assets,
        'stored_assets': stored_assets,
        'lost_assets': lost_assets,
        'disposed_assets': disposed_assets,

        'total_activities': total_activities,
        'completed_activities': completed_activities,
        'pending_activities': pending_activities,

        'total_maintenance': total_maintenance,
        'completed_maintenance': completed_maintenance,
        'pending_maintenance': pending_maintenance,
        'in_progress_maintenance': in_progress_maintenance,
    }

    return render(
        request,
        'dashboard/reports.html',
        context
    )
    
BACKUP_NAME_RE = re.compile(
    r'^IT_Management_Backup_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.backup$'
)


def _backup_dir():
    path = Path(settings.BACKUP_DIR)
    path.mkdir(parents=True, exist_ok=True)
    return path.resolve()


def _resolve_backup(filename):
    """
    مسیر امن فایل بکاپ را برمی‌گرداند یا None.
    جلوگیری از Path Traversal: فقط نام‌های دقیقاً با الگوی بکاپ پذیرفته می‌شوند
    و مسیر نهایی باید داخل پوشه‌ی بکاپ باشد.
    """
    if not BACKUP_NAME_RE.match(filename or ''):
        return None
    base = _backup_dir()
    candidate = (base / filename).resolve()
    if candidate.parent != base or not candidate.is_file():
        return None
    return candidate


def _find_pg_dump():
    """pg_dump را از تنظیمات، PATH یا مسیرهای رایج نصب PostgreSQL پیدا می‌کند."""
    configured = str(settings.PG_DUMP_PATH or '').replace('\\\\'[:0] + chr(92)*2, chr(92))
    if configured and os.path.isfile(configured):
        return configured

    found = shutil.which('pg_dump')
    if found:
        return found

    candidates = []
    for root in (os.environ.get('ProgramFiles', r'C:\Program Files'),
                 os.environ.get('ProgramFiles(x86)', r'C:\Program Files (x86)')):
        candidates += glob.glob(os.path.join(root, 'PostgreSQL', '*', 'bin', 'pg_dump.exe'))
    candidates += glob.glob(r'C:\xampp\pgsql\bin\pg_dump.exe')
    candidates += ['/usr/bin/pg_dump', '/usr/local/bin/pg_dump']
    existing = [c for c in candidates if os.path.isfile(c)]
    # جدیدترین نسخه
    return sorted(existing)[-1] if existing else None


def _explain_pg_dump_error(stderr):
    """علت خطا را برای مدیر (staff) خلاصه و بدون افشای رمز برمی‌گرداند."""
    text = (stderr or '').lower()
    if 'server version' in text and 'mismatch' in text:
        return 'نسخه‌ی pg_dump از نسخه‌ی سرور PostgreSQL قدیمی‌تر است؛ pg_dump هم‌نسخه (یا جدیدتر) نصب کنید و PG_DUMP_PATH را به آن بدهید.'
    if 'password authentication failed' in text or 'no password supplied' in text:
        return 'احراز هویت دیتابیس ناموفق بود؛ DB_USER و DB_PASSWORD را در .env بررسی کنید.'
    if 'could not connect' in text or 'connection refused' in text or 'timeout expired' in text:
        return 'اتصال به سرور PostgreSQL برقرار نشد؛ سرویس PostgreSQL، DB_HOST و DB_PORT را بررسی کنید.'
    if 'does not exist' in text and 'database' in text:
        return 'دیتابیس با نام DB_NAME پیدا نشد.'
    if 'permission denied' in text:
        return 'دسترسی نوشتن در پوشه‌ی بکاپ یا خواندن جداول وجود ندارد.'
    return 'خطای نامشخص از pg_dump؛ جزئیات در لاگ سرور (کنسول) ثبت شد.'


@staff_required
@require_POST
def database_backup(request):
    db = settings.DATABASES['default']

    if 'postgresql' not in db['ENGINE']:
        messages.error(request, 'پشتیبان‌گیری فقط برای PostgreSQL پشتیبانی می‌شود.')
        return redirect('backup_list')

    backup_dir = _backup_dir()
    timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    filename = f'IT_Management_Backup_{timestamp}.backup'
    backup_path = backup_dir / filename

    pg_dump = _find_pg_dump()
    if not pg_dump:
        logger.error('pg_dump not found. PG_DUMP_PATH=%r', settings.PG_DUMP_PATH)
        messages.error(
            request,
            'برنامه‌ی pg_dump پیدا نشد. PostgreSQL را نصب کنید یا در فایل .env مسیر '
            'PG_DUMP_PATH را دقیقاً روی pg_dump.exe تنظیم کنید '
            '(مثلاً C:\\Program Files\\PostgreSQL\\16\\bin\\pg_dump.exe).'
        )
        return redirect('backup_list')

    command = [
        pg_dump,
        '-h', db['HOST'] or '127.0.0.1',
        '-p', str(db['PORT'] or '5432'),
        '-U', db['USER'],
        '-F', 'c',
        '-b',
        '-f', str(backup_path),
        db['NAME'],
    ]

    env = os.environ.copy()
    env['PGPASSWORD'] = db['PASSWORD']

    try:
        subprocess.run(
            command, env=env, check=True, capture_output=True, text=True, timeout=300
        )
    except subprocess.CalledProcessError as exc:
        logger.error('pg_dump failed (code %s): %s', exc.returncode, exc.stderr)
        backup_path.unlink(missing_ok=True)
        messages.error(request, 'ایجاد پشتیبان ناموفق بود: ' + _explain_pg_dump_error(exc.stderr))
        return redirect('backup_list')
    except subprocess.TimeoutExpired:
        logger.error('pg_dump timed out')
        backup_path.unlink(missing_ok=True)
        messages.error(request, 'پشتیبان‌گیری بیش از ۵ دقیقه طول کشید و متوقف شد.')
        return redirect('backup_list')
    except OSError:
        logger.exception('pg_dump could not be executed')
        messages.error(request, 'اجرای pg_dump ممکن نشد؛ مسیر PG_DUMP_PATH و دسترسی‌ها را بررسی کنید.')
        return redirect('backup_list')

    logger.info('Backup created by %s: %s', request.user.username, filename)
    return FileResponse(open(backup_path, 'rb'), as_attachment=True, filename=filename)


@staff_required
def backup_list(request):
    backups = []

    for item in _backup_dir().iterdir():
        if item.is_file() and BACKUP_NAME_RE.match(item.name):
            stat = item.stat()
            backups.append({
                'filename': item.name,
                'size': stat.st_size,
                'modified': datetime.fromtimestamp(stat.st_mtime),
            })

    backups.sort(key=lambda x: x['modified'], reverse=True)

    return render(request, 'dashboard/backup_list.html', {'backups': backups})


@staff_required
def backup_download(request, filename):
    file_path = _resolve_backup(filename)

    if file_path is None:
        messages.error(request, 'فایل Backup مورد نظر پیدا نشد.')
        return redirect('backup_list')

    logger.info('Backup downloaded by %s: %s', request.user.username, filename)
    return FileResponse(open(file_path, 'rb'), as_attachment=True, filename=file_path.name)


@staff_required
@require_POST
def backup_delete(request, filename):
    file_path = _resolve_backup(filename)

    if file_path is None:
        messages.error(request, 'فایل Backup مورد نظر پیدا نشد.')
        return redirect('backup_list')

    try:
        file_path.unlink()
        logger.info('Backup deleted by %s: %s', request.user.username, filename)
        messages.success(request, f'Backup «{filename}» با موفقیت حذف شد.')
    except OSError:
        logger.exception('Backup delete failed')
        messages.error(request, 'حذف Backup با مشکل مواجه شد.')

    return redirect('backup_list')


@login_required(login_url='login')
def quick_search(request):
    query = request.GET.get('q', '').strip()

    assets = []
    facilities = []

    if query:
        assets = Asset.objects.filter(
            Q(asset_code__icontains=query) |
            Q(name__icontains=query) |
            Q(brand__icontains=query) |
            Q(model__icontains=query) |
            Q(serial_number__icontains=query)
        ).select_related(
            'category',
            'location'
        )[:5]

        facilities = Facility.objects.filter(
            Q(code__icontains=query) |
            Q(name__icontains=query) |
            Q(room_number__icontains=query) |
            Q(building__icontains=query)
        )[:5]

    return render(
        request,
        'dashboard/quick_search.html',
        {
            'query': query,
            'assets': assets,
            'facilities': facilities,
        }
    )
    
    
@login_required(login_url='login')
def comprehensive_report(request):

    date_from = request.GET.get('date_from', '').strip()
    date_to = request.GET.get('date_to', '').strip()

    # =========================================================
    # Facilities
    # =========================================================
    total_facilities = Facility.objects.count()

    facility_types = {
        'CLASSROOM': Facility.objects.filter(
            facility_type='CLASSROOM'
        ).count(),

        'LABORATORY': Facility.objects.filter(
            facility_type='LABORATORY'
        ).count(),

        'OFFICE': Facility.objects.filter(
            facility_type='OFFICE'
        ).count(),

        'MEETING_ROOM': Facility.objects.filter(
            facility_type='MEETING_ROOM'
        ).count(),

        'SERVER_ROOM': Facility.objects.filter(
            facility_type='SERVER_ROOM'
        ).count(),

        'STORE': Facility.objects.filter(
            facility_type='STORE'
        ).count(),

        'OTHER': Facility.objects.filter(
            facility_type='OTHER'
        ).count(),
    }

    active_facilities = Facility.objects.filter(
        status='ACTIVE'
    ).count()

    inactive_facilities = Facility.objects.filter(
        status='INACTIVE'
    ).count()

    # =========================================================
    # Assets
    # =========================================================
    total_assets = Asset.objects.count()

    asset_status = {
        'ACTIVE': Asset.objects.filter(
            status='ACTIVE'
        ).count(),

        'DAMAGED': Asset.objects.filter(
            status='DAMAGED'
        ).count(),

        'UNDER_REPAIR': Asset.objects.filter(
            status='UNDER_REPAIR'
        ).count(),

        'STORED': Asset.objects.filter(
            status='STORED'
        ).count(),

        'LOST': Asset.objects.filter(
            status='LOST'
        ).count(),

        'DISPOSED': Asset.objects.filter(
            status='DISPOSED'
        ).count(),
    }

    # =========================================================
    # Activities
    # =========================================================
    activities = Activity.objects.all()

    if date_from:
        activities = activities.filter(
            date__gte=date_from
        )

    if date_to:
        activities = activities.filter(
            date__lte=date_to
        )

    total_activities = activities.count()

    completed_activities = activities.filter(
        status='COMPLETED'
    ).count()

    pending_activities = activities.filter(
        status='PENDING'
    ).count()

    in_progress_activities = activities.filter(
        status='IN_PROGRESS'
    ).count()

    cancelled_activities = activities.filter(
        status='CANCELLED'
    ).count()

    urgent_activities = activities.filter(
        priority='HIGH'
    ).count()

    # =========================================================
    # Maintenance
    # =========================================================
    maintenances = Maintenance.objects.all()

    if date_from:
        maintenances = maintenances.filter(
            report_date__gte=date_from
        )

    if date_to:
        maintenances = maintenances.filter(
            report_date__lte=date_to
        )

    total_maintenance = maintenances.count()

    completed_maintenance = maintenances.filter(
        status='COMPLETED'
    ).count()

    pending_maintenance = maintenances.filter(
        status='PENDING'
    ).count()

    in_progress_maintenance = maintenances.filter(
        status='IN_PROGRESS'
    ).count()

    sent_out_maintenance = maintenances.filter(
        status='SENT_OUT'
    ).count()

    not_repairable_maintenance = maintenances.filter(
        status='NOT_REPAIRABLE'
    ).count()

    # =========================================================
    # موارد نیازمند توجه
    # =========================================================
    attention_items = []

    if asset_status['DAMAGED'] > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'تجهیزات خراب',
            'count': asset_status['DAMAGED'],
            'text': 'تجهیز خراب نیازمند بررسی و رسیدگی است.'
        })

    if asset_status['UNDER_REPAIR'] > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'تجهیزات تحت ترمیم',
            'count': asset_status['UNDER_REPAIR'],
            'text': 'تجهیز تحت ترمیم قرار دارد.'
        })

    if asset_status['LOST'] > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'تجهیزات مفقود',
            'count': asset_status['LOST'],
            'text': 'تجهیز مفقود ثبت شده است.'
        })

    if urgent_activities > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'فعالیت‌های عاجل',
            'count': urgent_activities,
            'text': 'فعالیت عاجل نیازمند رسیدگی است.'
        })

    if pending_activities > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'فعالیت‌های در انتظار',
            'count': pending_activities,
            'text': 'فعالیت در انتظار اجرا قرار دارد.'
        })

    if in_progress_activities > 0:
        attention_items.append({
            'type': 'info',
            'title': 'فعالیت‌های در حال اجرا',
            'count': in_progress_activities,
            'text': 'فعالیت در حال اجرا می‌باشد.'
        })

    if pending_maintenance > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'تعمیرات در انتظار',
            'count': pending_maintenance,
            'text': 'مورد تعمیراتی در انتظار رسیدگی است.'
        })

    if in_progress_maintenance > 0:
        attention_items.append({
            'type': 'info',
            'title': 'تعمیرات در حال اجرا',
            'count': in_progress_maintenance,
            'text': 'مورد تعمیراتی در حال اجرا است.'
        })

    if not_repairable_maintenance > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'غیرقابل تعمیر',
            'count': not_repairable_maintenance,
            'text': 'مورد تعمیراتی غیرقابل تعمیر ثبت شده است.'
        })

    # =========================================================
    # Context
    # =========================================================
    context = {
        # Date range
        'date_from': date_from,
        'date_to': date_to,

        # Facilities
        'total_facilities': total_facilities,
        'facility_types': facility_types,
        'active_facilities': active_facilities,
        'inactive_facilities': inactive_facilities,

        # Assets
        'total_assets': total_assets,
        'asset_status': asset_status,

        # Activities
        'total_activities': total_activities,
        'completed_activities': completed_activities,
        'pending_activities': pending_activities,
        'in_progress_activities': in_progress_activities,
        'cancelled_activities': cancelled_activities,
        'urgent_activities': urgent_activities,

        # Maintenance
        'total_maintenance': total_maintenance,
        'completed_maintenance': completed_maintenance,
        'pending_maintenance': pending_maintenance,
        'in_progress_maintenance': in_progress_maintenance,
        'sent_out_maintenance': sent_out_maintenance,
        'not_repairable_maintenance': not_repairable_maintenance,

        # Attention
        'attention_items': attention_items,
    }

    return render(
        request,
        'dashboard/comprehensive_report.html',
        context
    )
    
    
@login_required(login_url='login')
def comprehensive_report_print(request):

    date_from = request.GET.get('date_from', '').strip()
    date_to = request.GET.get('date_to', '').strip()

    # =========================================================
    # Facilities
    # =========================================================
    total_facilities = Facility.objects.count()

    facility_types = {
        'CLASSROOM': Facility.objects.filter(
            facility_type='CLASSROOM'
        ).count(),

        'LABORATORY': Facility.objects.filter(
            facility_type='LABORATORY'
        ).count(),

        'OFFICE': Facility.objects.filter(
            facility_type='OFFICE'
        ).count(),

        'MEETING_ROOM': Facility.objects.filter(
            facility_type='MEETING_ROOM'
        ).count(),

        'SERVER_ROOM': Facility.objects.filter(
            facility_type='SERVER_ROOM'
        ).count(),

        'STORE': Facility.objects.filter(
            facility_type='STORE'
        ).count(),

        'OTHER': Facility.objects.filter(
            facility_type='OTHER'
        ).count(),
    }

    active_facilities = Facility.objects.filter(
        status='ACTIVE'
    ).count()

    inactive_facilities = Facility.objects.filter(
        status='INACTIVE'
    ).count()

    # =========================================================
    # Assets
    # =========================================================
    total_assets = Asset.objects.count()

    asset_status = {
        'ACTIVE': Asset.objects.filter(
            status='ACTIVE'
        ).count(),

        'DAMAGED': Asset.objects.filter(
            status='DAMAGED'
        ).count(),

        'UNDER_REPAIR': Asset.objects.filter(
            status='UNDER_REPAIR'
        ).count(),

        'STORED': Asset.objects.filter(
            status='STORED'
        ).count(),

        'LOST': Asset.objects.filter(
            status='LOST'
        ).count(),

        'DISPOSED': Asset.objects.filter(
            status='DISPOSED'
        ).count(),
    }

    # =========================================================
    # Activities
    # =========================================================
    activities = Activity.objects.all()

    if date_from:
        activities = activities.filter(
            date__gte=date_from
        )

    if date_to:
        activities = activities.filter(
            date__lte=date_to
        )

    total_activities = activities.count()

    completed_activities = activities.filter(
        status='COMPLETED'
    ).count()

    pending_activities = activities.filter(
        status='PENDING'
    ).count()

    in_progress_activities = activities.filter(
        status='IN_PROGRESS'
    ).count()

    cancelled_activities = activities.filter(
        status='CANCELLED'
    ).count()

    urgent_activities = activities.filter(
        priority='HIGH'
    ).count()

    # =========================================================
    # Maintenance
    # =========================================================
    maintenances = Maintenance.objects.all()

    if date_from:
        maintenances = maintenances.filter(
            report_date__gte=date_from
        )

    if date_to:
        maintenances = maintenances.filter(
            report_date__lte=date_to
        )

    total_maintenance = maintenances.count()

    completed_maintenance = maintenances.filter(
        status='COMPLETED'
    ).count()

    pending_maintenance = maintenances.filter(
        status='PENDING'
    ).count()

    in_progress_maintenance = maintenances.filter(
        status='IN_PROGRESS'
    ).count()

    sent_out_maintenance = maintenances.filter(
        status='SENT_OUT'
    ).count()

    not_repairable_maintenance = maintenances.filter(
        status='NOT_REPAIRABLE'
    ).count()

    # =========================================================
    # موارد نیازمند توجه
    # =========================================================
    attention_items = []

    if asset_status['DAMAGED'] > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'تجهیزات خراب',
            'count': asset_status['DAMAGED'],
            'text': 'تجهیز خراب نیازمند بررسی و رسیدگی است.'
        })

    if asset_status['UNDER_REPAIR'] > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'تجهیزات تحت ترمیم',
            'count': asset_status['UNDER_REPAIR'],
            'text': 'تجهیز تحت ترمیم قرار دارد.'
        })

    if asset_status['LOST'] > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'تجهیزات مفقود',
            'count': asset_status['LOST'],
            'text': 'تجهیز مفقود ثبت شده است.'
        })

    if urgent_activities > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'فعالیت‌های عاجل',
            'count': urgent_activities,
            'text': 'فعالیت عاجل نیازمند رسیدگی است.'
        })

    if pending_activities > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'فعالیت‌های در انتظار',
            'count': pending_activities,
            'text': 'فعالیت در انتظار اجرا قرار دارد.'
        })

    if in_progress_activities > 0:
        attention_items.append({
            'type': 'info',
            'title': 'فعالیت‌های در حال اجرا',
            'count': in_progress_activities,
            'text': 'فعالیت در حال اجرا می‌باشد.'
        })

    if pending_maintenance > 0:
        attention_items.append({
            'type': 'warning',
            'title': 'تعمیرات در انتظار',
            'count': pending_maintenance,
            'text': 'مورد تعمیراتی در انتظار رسیدگی است.'
        })

    if in_progress_maintenance > 0:
        attention_items.append({
            'type': 'info',
            'title': 'تعمیرات در حال اجرا',
            'count': in_progress_maintenance,
            'text': 'مورد تعمیراتی در حال اجرا است.'
        })

    if not_repairable_maintenance > 0:
        attention_items.append({
            'type': 'danger',
            'title': 'غیرقابل تعمیر',
            'count': not_repairable_maintenance,
            'text': 'مورد تعمیراتی غیرقابل تعمیر ثبت شده است.'
        })

    # =========================================================
    # Context
    # =========================================================
    context = {
        'date_from': date_from,
        'date_to': date_to,

        'total_facilities': total_facilities,
        'facility_types': facility_types,
        'active_facilities': active_facilities,
        'inactive_facilities': inactive_facilities,

        'total_assets': total_assets,
        'asset_status': asset_status,

        'total_activities': total_activities,
        'completed_activities': completed_activities,
        'pending_activities': pending_activities,
        'in_progress_activities': in_progress_activities,
        'cancelled_activities': cancelled_activities,
        'urgent_activities': urgent_activities,

        'total_maintenance': total_maintenance,
        'completed_maintenance': completed_maintenance,
        'pending_maintenance': pending_maintenance,
        'in_progress_maintenance': in_progress_maintenance,
        'sent_out_maintenance': sent_out_maintenance,
        'not_repairable_maintenance': not_repairable_maintenance,

        'attention_items': attention_items,
    }

    return render(
        request,
        'dashboard/comprehensive_report_print.html',
        context
    )    
    
    
@login_required(login_url='login')
def comprehensive_report_excel(request):

    from openpyxl import Workbook
    from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
    from openpyxl.utils import get_column_letter
    from openpyxl.worksheet.page import PageMargins
    from django.http import HttpResponse

    date_from = request.GET.get('date_from', '').strip()
    date_to = request.GET.get('date_to', '').strip()

    # =========================
    # Facilities
    # =========================
    total_facilities = Facility.objects.count()
    active_facilities = Facility.objects.filter(status='ACTIVE').count()
    inactive_facilities = Facility.objects.filter(status='INACTIVE').count()

    facility_types = {
        'صنف': Facility.objects.filter(facility_type='CLASSROOM').count(),
        'لابراتوار': Facility.objects.filter(facility_type='LABORATORY').count(),
        'دفتر': Facility.objects.filter(facility_type='OFFICE').count(),
        'اتاق جلسه': Facility.objects.filter(facility_type='MEETING_ROOM').count(),
        'سرور روم': Facility.objects.filter(facility_type='SERVER_ROOM').count(),
        'گدام': Facility.objects.filter(facility_type='STORE').count(),
        'سایر': Facility.objects.filter(facility_type='OTHER').count(),
    }

    # =========================
    # Assets
    # =========================
    total_assets = Asset.objects.count()

    asset_status = {
        'فعال': Asset.objects.filter(status='ACTIVE').count(),
        'خراب': Asset.objects.filter(status='DAMAGED').count(),
        'تحت ترمیم': Asset.objects.filter(status='UNDER_REPAIR').count(),
        'در گدام': Asset.objects.filter(status='STORED').count(),
        'مفقود': Asset.objects.filter(status='LOST').count(),
        'خارج شده': Asset.objects.filter(status='DISPOSED').count(),
    }

    # =========================
    # Activities
    # =========================
    activities = Activity.objects.all()

    if date_from:
        activities = activities.filter(date__gte=date_from)

    if date_to:
        activities = activities.filter(date__lte=date_to)

    total_activities = activities.count()
    completed_activities = activities.filter(status='COMPLETED').count()
    pending_activities = activities.filter(status='PENDING').count()
    in_progress_activities = activities.filter(status='IN_PROGRESS').count()
    cancelled_activities = activities.filter(status='CANCELLED').count()
    urgent_activities = activities.filter(priority='HIGH').count()

    # =========================
    # Maintenance
    # =========================
    maintenances = Maintenance.objects.all()

    if date_from:
        maintenances = maintenances.filter(report_date__gte=date_from)

    if date_to:
        maintenances = maintenances.filter(report_date__lte=date_to)

    total_maintenance = maintenances.count()
    completed_maintenance = maintenances.filter(status='COMPLETED').count()
    pending_maintenance = maintenances.filter(status='PENDING').count()
    in_progress_maintenance = maintenances.filter(status='IN_PROGRESS').count()
    sent_out_maintenance = maintenances.filter(status='SENT_OUT').count()
    not_repairable_maintenance = maintenances.filter(
        status='NOT_REPAIRABLE'
    ).count()

    # =========================
    # Excel
    # =========================
    wb = Workbook()
    ws = wb.active
    ws.title = "گزارش جامع IT"

    # RTL
    ws.sheet_view.rightToLeft = True

    # Styles
    title_font = Font(
        name='B Nazanin',
        size=16,
        bold=True
    )

    subtitle_font = Font(
        name='B Nazanin',
        size=13,
        bold=True
    )

    normal_font = Font(
        name='B Nazanin',
        size=11
    )

    header_font = Font(
        name='B Nazanin',
        size=11,
        bold=True,
        color='FFFFFF'
    )

    header_fill = PatternFill(
        'solid',
        fgColor='1F4E78'
    )

    section_fill = PatternFill(
        'solid',
        fgColor='D9EAF7'
    )

    thin = Side(
        style='thin',
        color='B7B7B7'
    )

    border = Border(
        left=thin,
        right=thin,
        top=thin,
        bottom=thin
    )

    center = Alignment(
        horizontal='center',
        vertical='center'
    )

    right = Alignment(
        horizontal='right',
        vertical='center'
    )

    # =========================
    # Official Header
    # =========================

    ws.merge_cells('A1:D1')
    ws['A1'] = 'امارت اسلامی افغانستان'
    ws['A1'].font = title_font
    ws['A1'].alignment = center

    ws.merge_cells('A2:D2')
    ws['A2'] = 'وزارت تحصیلات عالی'
    ws['A2'].font = subtitle_font
    ws['A2'].alignment = center

    ws.merge_cells('A3:D3')
    ws['A3'] = 'پوهنتون طبی چراغ'
    ws['A3'].font = subtitle_font
    ws['A3'].alignment = center

    ws.merge_cells('A4:D4')
    ws['A4'] = 'آمریت تکنالوژی معلوماتی'
    ws['A4'].font = subtitle_font
    ws['A4'].alignment = center

    ws.merge_cells('A5:D5')
    ws['A5'] = 'گزارش جامع وضعیت تکنالوژی معلوماتی'
    ws['A5'].font = Font(
        name='B Nazanin',
        size=15,
        bold=True
    )
    ws['A5'].alignment = center

    # Date range
    ws.merge_cells('A7:D7')

    if date_from or date_to:
        date_text = f'بازه گزارش: {date_from or "ابتدا"} تا {date_to or "امروز"}'
    else:
        date_text = 'بازه گزارش: تمام اطلاعات ثبت‌شده'

    ws['A7'] = date_text
    ws['A7'].font = normal_font
    ws['A7'].alignment = center

    # =========================
    # Summary
    # =========================

    row = 9

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = 'خلاصه گزارش'
    ws.cell(row=row, column=1).font = subtitle_font
    ws.cell(row=row, column=1).fill = section_fill
    ws.cell(row=row, column=1).alignment = right

    row += 1

    summary_headers = ['مورد', 'تعداد']

    ws.cell(row=row, column=1).value = summary_headers[0]
    ws.cell(row=row, column=2).value = summary_headers[1]

    for col in range(1, 3):
        cell = ws.cell(row=row, column=col)
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = center
        cell.border = border

    row += 1

    summary_data = [
        ('مجموع مکان‌ها', total_facilities),
        ('مجموع تجهیزات', total_assets),
        ('مجموع فعالیت‌ها', total_activities),
        ('مجموع تعمیرات', total_maintenance),
    ]

    for label, count in summary_data:
        ws.cell(row=row, column=1).value = label
        ws.cell(row=row, column=2).value = count

        for col in range(1, 3):
            cell = ws.cell(row=row, column=col)
            cell.font = normal_font
            cell.alignment = right if col == 1 else center
            cell.border = border

        row += 1

    # =========================
    # Facilities
    # =========================

    row += 1

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = 'مکان‌ها'
    ws.cell(row=row, column=1).font = subtitle_font
    ws.cell(row=row, column=1).fill = section_fill
    ws.cell(row=row, column=1).alignment = right

    row += 1

    facility_data = [
        ('فعال', active_facilities),
        ('غیرفعال', inactive_facilities),
    ]

    facility_data += list(facility_types.items())

    for label, count in facility_data:
        ws.cell(row=row, column=1).value = label
        ws.cell(row=row, column=2).value = count

        for col in range(1, 3):
            cell = ws.cell(row=row, column=col)
            cell.font = normal_font
            cell.alignment = right if col == 1 else center
            cell.border = border

        row += 1

    # =========================
    # Assets
    # =========================

    row += 1

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = 'تجهیزات'
    ws.cell(row=row, column=1).font = subtitle_font
    ws.cell(row=row, column=1).fill = section_fill
    ws.cell(row=row, column=1).alignment = right

    row += 1

    for label, count in asset_status.items():
        ws.cell(row=row, column=1).value = label
        ws.cell(row=row, column=2).value = count

        for col in range(1, 3):
            cell = ws.cell(row=row, column=col)
            cell.font = normal_font
            cell.alignment = right if col == 1 else center
            cell.border = border

        row += 1

    # =========================
    # Activities
    # =========================

    row += 1

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = 'فعالیت‌ها'
    ws.cell(row=row, column=1).font = subtitle_font
    ws.cell(row=row, column=1).fill = section_fill
    ws.cell(row=row, column=1).alignment = right

    row += 1

    activity_data = [
        ('تکمیل شده', completed_activities),
        ('در انتظار', pending_activities),
        ('در حال اجرا', in_progress_activities),
        ('لغو شده', cancelled_activities),
        ('عاجل', urgent_activities),
    ]

    for label, count in activity_data:
        ws.cell(row=row, column=1).value = label
        ws.cell(row=row, column=2).value = count

        for col in range(1, 3):
            cell = ws.cell(row=row, column=col)
            cell.font = normal_font
            cell.alignment = right if col == 1 else center
            cell.border = border

        row += 1

    # =========================
    # Maintenance
    # =========================

    row += 1

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = 'تعمیرات'
    ws.cell(row=row, column=1).font = subtitle_font
    ws.cell(row=row, column=1).fill = section_fill
    ws.cell(row=row, column=1).alignment = right

    row += 1

    maintenance_data = [
        ('تکمیل شده', completed_maintenance),
        ('در انتظار تعمیر', pending_maintenance),
        ('در حال تعمیر', in_progress_maintenance),
        ('ارسال شده به بیرون', sent_out_maintenance),
        ('غیرقابل تعمیر', not_repairable_maintenance),
    ]

    for label, count in maintenance_data:
        ws.cell(row=row, column=1).value = label
        ws.cell(row=row, column=2).value = count

        for col in range(1, 3):
            cell = ws.cell(row=row, column=col)
            cell.font = normal_font
            cell.alignment = right if col == 1 else center
            cell.border = border

        row += 1

    # =========================
    # Conclusion
    # =========================

    row += 1

    ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=4)
    ws.cell(row=row, column=1).value = (
        'این گزارش بر اساس اطلاعات ثبت‌شده در سیستم مدیریت '
        'تکنالوژی معلوماتی تهیه شده است.'
    )
    ws.cell(row=row, column=1).font = normal_font
    ws.cell(row=row, column=1).alignment = right

    # =========================
    # Column Width
    # =========================

    ws.column_dimensions['A'].width = 32
    ws.column_dimensions['B'].width = 18
    ws.column_dimensions['C'].width = 18
    ws.column_dimensions['D'].width = 18

    # =========================
    # Page Setup
    # =========================

    ws.page_setup.orientation = 'portrait'
    ws.page_setup.paperSize = ws.PAPERSIZE_A4
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 0

    ws.sheet_properties.pageSetUpPr.fitToPage = True

    ws.page_margins = PageMargins(
        left=0.3,
        right=0.3,
        top=0.5,
        bottom=0.5,
        header=0.2,
        footer=0.2
    )

    ws.print_title_rows = '1:7'
    ws.freeze_panes = 'A9'

    # =========================
    # Response
    # =========================

    response = HttpResponse(
        content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    )

    response['Content-Disposition'] = (
        'attachment; filename="IT_Comprehensive_Report.xlsx"'
    )

    sanitize_workbook(wb)
    wb.save(response)

    return response    