import calendar
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
from django.utils import timezone
from django.contrib import messages
from .models import ClientProfile
from .forms import PortalLoginForm
from task_management.models import DocumentRequest, AssetRequest, ActivityLog
from django.http import JsonResponse, FileResponse, Http404
from system.workflow_services import notify_users
from task_management.models import SystemNotification
from system.access_policy import get_default_dashboard_url


def login_view(request):
    if request.user.is_authenticated:
        return redirect(get_default_dashboard_url(request.user))

    if request.method == 'POST':
        form = PortalLoginForm(request, data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            route = get_default_dashboard_url(user)
            if route == 'client_portal:login':
                logout(request)
                messages.error(request, 'No portal access configured for this account.')
            else:
                return redirect(route)
        else:
            messages.error(request, 'Invalid email or password.')
    else:
        form = PortalLoginForm()

    return render(request, 'portal/login.html', {'form': form})


def logout_view(request):
    logout(request)
    return redirect('client_portal:login')


def get_client_project(request):
    """Helper: get the ClientProfile and active Project or None."""
    profile = get_object_or_404(ClientProfile, user=request.user)
    project = profile.active_project
    return profile, project


@login_required
def dashboard_view(request):
    profile, project = get_client_project(request)

    if not project:
        return render(request, 'portal/dashboard.html', {
            'profile': profile,
            'project': None,
            'active_page': 'dashboard',
        })

    unsigned_docs = project.document_requests.filter(
        is_active=True, portal_visible=True, signed=False
    )
    missing_assets = project.asset_requests.filter(
        is_active=True, portal_visible=True, required=True, status='requested'
    )

    can_approve_completion = (
        project.progress_percentage == 100
        and project.status not in ('completed', 'cancelled')
    )

    context = {
        'profile': profile,
        'project': project,
        'unsigned_docs': unsigned_docs,
        'missing_assets': missing_assets,
        'active_page': 'dashboard',
        'can_approve_completion': can_approve_completion,
    }
    return render(request, 'portal/dashboard.html', context)


@login_required
def documents_view(request):
    profile, project = get_client_project(request)
    if not project:
        return redirect('client_portal:dashboard')

    documents = project.document_requests.filter(is_active=True, portal_visible=True)
    pending_count = documents.filter(signed=False).count()

    return render(request, 'portal/documents.html', {
        'profile': profile,
        'project': project,
        'documents': documents,
        'pending_count': pending_count,
        'active_page': 'documents',
    })


@login_required
@require_POST
def sign_document_view(request, doc_id):
    profile, project = get_client_project(request)
    document = get_object_or_404(
        DocumentRequest, id=doc_id, project=project,
        portal_visible=True, is_active=True
    )

    signature_name = request.POST.get('signature_name', '').strip()
    agree = request.POST.get('agree') in ('on', 'true')
    signed_file = request.FILES.get('signed_file')

    if len(signature_name) < 3 or not agree:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': False, 'error': 'Please type your full name and check the agreement box.'}, status=400)
        messages.error(request, 'Please provide a valid signature.')
        return redirect('client_portal:documents')

    if not signed_file:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': False, 'error': 'Please upload the signed document.'}, status=400)
        messages.error(request, 'Please upload the signed document.')
        return redirect('client_portal:documents')

    document.signed = True
    document.signed_by = signature_name
    document.signed_at = timezone.now()
    document.signed_file = signed_file
    document.status = 'signed'
    document.save()

    ActivityLog.log(request.user, 'signed', document, project=project,
                    details=f'Signed by {signature_name}, file: {signed_file.name}')
    notify_users(
        users=project.team_members.all(),
        title=f'Client signed: {document.title}',
        message=f'{profile.user.get_full_name()} signed a document.',
        category='document',
        link=f'/staff/projects/{project.id}/documents/'
    )

    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'success': True,
            'message': f'"{document.title}" signed successfully.',
            'pending_count': project.pending_documents_count,
            'missing_assets': project.missing_assets_count,
        })

    messages.success(request, f'"{document.title}" signed successfully.')
    return redirect('client_portal:documents')


@login_required
def get_document_detail(request, doc_id):
    profile, project = get_client_project(request)
    document = get_object_or_404(
        DocumentRequest, id=doc_id, project=project,
        portal_visible=True, is_active=True
    )
    return JsonResponse({
        'id': document.id,
        'title': document.title,
        'preview': document.preview_text or document.description,
        'signed': document.signed,
    })


@login_required
def assets_view(request):
    profile, project = get_client_project(request)
    if not project:
        return redirect('client_portal:dashboard')

    assets = project.asset_requests.filter(is_active=True, portal_visible=True)
    missing_count = assets.filter(required=True, status='requested').count()

    return render(request, 'portal/assets.html', {
        'profile': profile,
        'project': project,
        'assets': assets,
        'missing_count': missing_count,
        'active_page': 'assets',
    })


@login_required
@require_POST
def upload_asset_view(request, asset_id):
    profile, project = get_client_project(request)
    asset = get_object_or_404(
        AssetRequest, id=asset_id, project=project,
        portal_visible=True, is_active=True
    )

    uploaded_file = request.FILES.get('file')
    if not uploaded_file:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': False, 'error': 'No file provided'}, status=400)
        messages.error(request, 'No file provided.')
        return redirect('client_portal:assets')

    asset.file = uploaded_file
    asset.file_name = uploaded_file.name
    asset.status = 'uploaded'
    asset.uploaded_at = timezone.now()
    asset.save()

    ActivityLog.log(request.user, 'uploaded', asset, project=project,
                    details=f'Uploaded {uploaded_file.name}')
    notify_users(
        users=project.team_members.all(),
        title=f'Client uploaded: {asset.title}',
        message=f'{profile.user.get_full_name()} uploaded {uploaded_file.name}.',
        category='asset',
        link=f'/staff/projects/{project.id}/assets/'
    )

    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'success': True,
            'message': f'"{uploaded_file.name}" uploaded successfully.',
            'file_name': uploaded_file.name,
            'missing_assets': project.missing_assets_count,
            'pending_docs': project.pending_documents_count,
        })

    messages.success(request, f'"{uploaded_file.name}" uploaded successfully.')
    return redirect('client_portal:assets')


@login_required
def timeline_view(request):
    profile, project = get_client_project(request)
    if not project:
        return redirect('client_portal:dashboard')

    tasks = project.get_portal_timeline_tasks()
    total_days = project.total_project_days

    # Build month headers
    months = []
    cursor = project.start_date.replace(day=1)
    while cursor <= project.end_date:
        days_in_month = calendar.monthrange(cursor.year, cursor.month)[1]
        month_start = max(cursor, project.start_date)
        month_end_date = cursor.replace(day=days_in_month)
        month_end = min(month_end_date, project.end_date)
        effective_days = (month_end - month_start).days + 1
        months.append({'name': cursor.strftime('%b'), 'days': effective_days})
        if cursor.month == 12:
            cursor = cursor.replace(year=cursor.year + 1, month=1)
        else:
            cursor = cursor.replace(month=cursor.month + 1)

    task_data = []
    for task in tasks:
        assignees = list(task.assigned_to.all())
        task_data.append({
            'name': task.title,
            'team': 'Team',
            'status': task.gantt_status,
            'left_pct': task.left_percent(),
            'width_pct': task.width_percent(),
        })

    today_pct = (project.current_day / total_days * 100) if total_days > 0 else 0

    return render(request, 'portal/timeline.html', {
        'profile': profile,
        'project': project,
        'tasks': task_data,
        'months': months,
        'today_pct': today_pct,
        'active_page': 'timeline',
    })


@login_required
@require_POST
def notification_mark_read_view(request, notification_id):
    note = get_object_or_404(SystemNotification, id=notification_id, recipient=request.user)
    note.mark_read()
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        unread = request.user.system_notifications.filter(is_read=False).count()
        return JsonResponse({'success': True, 'unread': unread})
    return redirect(request.META.get('HTTP_REFERER', 'client_portal:dashboard'))


@login_required
def download_document(request, doc_id, file_type):
    profile, project = get_client_project(request)
    document = get_object_or_404(
        DocumentRequest, id=doc_id, project=project,
        portal_visible=True, is_active=True
    )
    if file_type == 'original' and document.file:
        return FileResponse(document.file.open('rb'), as_attachment=True,
                            filename=document.file.name.split('/')[-1])
    elif file_type == 'signed' and document.signed_file:
        return FileResponse(document.signed_file.open('rb'), as_attachment=True,
                            filename=document.signed_file.name.split('/')[-1])
    raise Http404("File not found")


@login_required
def download_asset(request, asset_id):
    profile, project = get_client_project(request)
    asset = get_object_or_404(
        AssetRequest, id=asset_id, project=project,
        portal_visible=True, is_active=True
    )
    if not asset.file:
        raise Http404("No file uploaded")
    return FileResponse(asset.file.open('rb'), as_attachment=True,
                        filename=asset.file_name or asset.file.name.split('/')[-1])


@login_required
def preview_asset(request, asset_id):
    profile, project = get_client_project(request)
    asset = get_object_or_404(
        AssetRequest, id=asset_id, project=project,
        portal_visible=True, is_active=True
    )
    file_name = asset.file_name or ''
    file_ext = file_name.rsplit('.', 1)[-1].lower() if '.' in file_name else ''
    is_image = file_ext in ('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg')
    return JsonResponse({
        'id': asset.id,
        'title': asset.title,
        'description': asset.description,
        'status': asset.get_status_display(),
        'required': asset.required,
        'has_file': bool(asset.file),
        'file_name': file_name,
        'file_url': asset.file.url if asset.file else None,
        'is_image': is_image,
        'uploaded_at': asset.uploaded_at.strftime('%d %b %Y, %H:%M') if asset.uploaded_at else None,
    })


# ─── Project Approval / Completion ───────────────────────────────────────────

@login_required
@require_POST
def project_approve_view(request):
    profile, project = get_client_project(request)
    if not project:
        messages.error(request, 'No active project found.')
        return redirect('client_portal:dashboard')

    if project.progress_percentage < 100:
        messages.error(request, 'Project must be 100% complete before approval.')
        return redirect('client_portal:dashboard')

    if project.status in ('completed', 'cancelled'):
        messages.error(request, 'Project is already finalised.')
        return redirect('client_portal:dashboard')

    feedback = request.POST.get('feedback', '').strip()
    project.status = 'completed'
    project.save()

    ActivityLog.log(
        request.user, 'updated', project, project=project,
        details=f'Client approved project completion. Feedback: {feedback}' if feedback else 'Client approved project completion.'
    )
    notify_users(
        users=project.team_members.all(),
        title=f'Project approved: {project.name}',
        message=f'{profile.user.get_full_name()} has formally approved the project as complete.'
                + (f' Feedback: {feedback}' if feedback else ''),
        category='task',
        link=f'/staff/projects/{project.id}/'
    )
    if project.project_manager:
        from system.workflow_services import notify_user
        notify_user(
            user=project.project_manager,
            title=f'Project approved by client: {project.name}',
            message=f'{profile.user.get_full_name()} has formally approved the project.'
                    + (f' Feedback: {feedback}' if feedback else ''),
            category='task',
            link=f'/staff/projects/{project.id}/'
        )

    messages.success(request, f'You have approved "{project.name}". Thank you!')
    return redirect('client_portal:dashboard')


@login_required
@require_POST
def project_request_changes_view(request):
    profile, project = get_client_project(request)
    if not project:
        messages.error(request, 'No active project found.')
        return redirect('client_portal:dashboard')

    feedback = request.POST.get('feedback', '').strip()
    if not feedback:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': False, 'error': 'Please describe the changes needed.'}, status=400)
        messages.error(request, 'Please describe the changes needed before submitting.')
        return redirect('client_portal:dashboard')

    ActivityLog.log(request.user, 'updated', project, project=project,
                    details=f'Client requested changes: {feedback}')
    notify_users(
        users=project.team_members.all(),
        title=f'Client requested changes: {project.name}',
        message=f'{profile.user.get_full_name()} has reviewed the project and requested changes: {feedback}',
        category='task',
        link=f'/staff/projects/{project.id}/'
    )
    if project.project_manager:
        from system.workflow_services import notify_user
        notify_user(
            user=project.project_manager,
            title=f'Change request from client: {project.name}',
            message=f'{profile.user.get_full_name()}: {feedback}',
            category='task',
            link=f'/staff/projects/{project.id}/'
        )

    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({'success': True, 'message': 'Your feedback has been sent to the team.'})

    messages.success(request, 'Your change request has been sent to the team.')
    return redirect('client_portal:dashboard')
