from django.contrib import messages
from django.db import connection
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.utils.translation import gettext_lazy as _

from horilla.decorators import (
    hx_request_required,
    login_required,
    manager_can_enter,
    owner_can_enter,
    permission_required,
)

from .forms import *
from .gdrive import *
from .pgdump import *
from .db_utils import is_supported_database
from .scheduler import *
from .zip import *

# @login_required
# @permission_required("backup.add_localbackup")
# def local_setup(request):
#     """
#     function used to setup local backup.

#     Parameters:
#     request (HttpRequest): The HTTP request object.

#     Returns:
#     GET : return local backup setup template
#     POST : return settings
#     """
#     form = LocalBackupSetupForm()
#     show = False
#     active = False
#     if LocalBackup.objects.exists():
#         form = LocalBackupSetupForm(instance=LocalBackup.objects.first())
#         show = True
#         active = LocalBackup.objects.first().active
#     if request.method == "POST":
#         form = LocalBackupSetupForm(request.POST, request.FILES)
#         if form.is_valid():
#             form.save()
#             stop_backup_job()
#             messages.success(request, _("Local backup automation setup updated."))
#             return redirect("local")
#     return render(request, "backup/local_setup_form.html", {"form": form, "show":show, "active":active})


# @login_required
# @permission_required("backup.change_localbackup")
# def local_Backup_stop_or_start(request):
#     """
#     function used to stop or start local backup.

#     Parameters:
#     request (HttpRequest): The HTTP request object.

#     Returns:
#     GET : return local backup setup template
#     POST : return settings
#     """
#     if LocalBackup.objects.exists():
#         local_backup = LocalBackup.objects.first()
#         if local_backup.active == True:
#             local_backup.active = False
#             stop_backup_job()
#             message = "Local Backup Automation Stopped Successfully."
#         else:
#             local_backup.active = True
#             start_backup_job()
#             message = "Local Backup Automation Started Successfully."
#         local_backup.save()
#         messages.success(request, _(message))
#     return redirect("local")


# @login_required
# @permission_required("backup.delete_localbackup")
# def local_Backup_delete(request):
#     """
#     function used to delete local backup.

#     Parameters:
#     request (HttpRequest): The HTTP request object.

#     Returns:
#     GET : return local backup setup template
#     POST : return settings
#     """
#     if LocalBackup.objects.exists():
#         local_backup = LocalBackup.objects.first()
#         local_backup.delete()
#         stop_backup_job()
#         messages.success(request, _("Local Backup Automation Removed Successfully."))
#     return redirect("local")


@login_required
@permission_required("backup.add_localbackup")
def gdrive_setup(request):
    """
    function used to setup gdrive backup.

    Parameters:
    request (HttpRequest): The HTTP request object.

    Returns:
    GET : return gdrive backup setup template
    POST : return gdrive backup update template
    """
    form = GdriveBackupSetupForm()
    show = False
    active = False
    if not is_supported_database():
        return render(request, "backup/404.html")
    if GoogleDriveBackup.objects.exists():
        instance = GoogleDriveBackup.objects.first()
        form = GdriveBackupSetupForm(instance=instance)
        show = True
        active = GoogleDriveBackup.objects.first().active
        if request.method == "POST":
            form = GdriveBackupSetupForm(request.POST, request.FILES, instance=instance)
            if form.is_valid():
                google_drive = form.save()
                google_drive.active = False
                google_drive.save()
                stop_gdrive_backup_job()
                
                # Validate the configuration based on authentication method
                try:
                    from .gdrive import validate_folder_access
                    
                    # Prepare auth parameters based on method
                    if google_drive.auth_method == 'service_account':
                        auth_params = {'service_account_file': google_drive.service_account_file.path}
                    elif google_drive.auth_method == 'oauth':
                        auth_params = {
                            'client_id': google_drive.oauth_client_id,
                            'client_secret': google_drive.oauth_client_secret,
                            'refresh_token': google_drive.oauth_refresh_token
                        }
                    else:
                        auth_params = {}
                    
                    validation = validate_folder_access(
                        google_drive.auth_method,
                        google_drive.gdrive_folder_id,
                        **auth_params
                    )
                    
                    if validation['success']:
                        messages.success(request, _("gdrive backup automation setup updated.") + f" {validation['message']}")
                    else:
                        messages.warning(request, _("gdrive backup automation setup updated.") + f" Warning: {validation['message']}")
                except Exception as e:
                    messages.warning(request, _("gdrive backup automation setup updated.") + f" Note: Could not validate configuration - {str(e)}")
                
                return redirect("gdrive")
        return render(
            request,
            "backup/gdrive_setup_form.html",
            {"form": form, "show": show, "active": active},
        )

    if request.method == "POST":
        form = GdriveBackupSetupForm(request.POST, request.FILES)
        if form.is_valid():
            google_drive = form.save()
            
            # Validate the configuration based on authentication method
            try:
                from .gdrive import validate_folder_access
                
                # Prepare auth parameters based on method
                if google_drive.auth_method == 'service_account':
                    auth_params = {'service_account_file': google_drive.service_account_file.path}
                elif google_drive.auth_method == 'oauth':
                    auth_params = {
                        'client_id': google_drive.oauth_client_id,
                        'client_secret': google_drive.oauth_client_secret,
                        'refresh_token': google_drive.oauth_refresh_token
                    }
                else:
                    auth_params = {}
                
                validation = validate_folder_access(
                    google_drive.auth_method,
                    google_drive.gdrive_folder_id,
                    **auth_params
                )
                
                if validation['success']:
                    messages.success(request, _("gdrive backup automation setup Created.") + f" {validation['message']}")
                else:
                    messages.warning(request, _("gdrive backup automation setup Created.") + f" Warning: {validation['message']}")
            except Exception as e:
                messages.warning(request, _("gdrive backup automation setup Created.") + f" Note: Could not validate configuration - {str(e)}")
                
            return redirect("gdrive")
    return render(
        request,
        "backup/gdrive_setup_form.html",
        {"form": form, "show": show, "active": active},
    )


@login_required
@permission_required("backup.change_localbackup")
def gdrive_Backup_stop_or_start(request):
    """
    function used to stop or start gdrive backup.

    Parameters:
    request (HttpRequest): The HTTP request object.

    Returns:
    GET : return gdrive backup setup template
    POST : return gdrive backup update template
    """
    if GoogleDriveBackup.objects.exists():
        gdive_backup = GoogleDriveBackup.objects.first()
        if gdive_backup.active == True:
            gdive_backup.active = False
            stop_gdrive_backup_job()
            message = "Gdrive Backup Automation Stopped Successfully."
        else:
            gdive_backup.active = True
            start_gdrive_backup_job()
            message = "Gdrive Backup Automation Started Successfully."
        gdive_backup.save()
        messages.success(request, _(message))
    return redirect("gdrive")


@login_required
@permission_required("backup.delete_localbackup")
def gdrive_Backup_delete(request):
    """
    function used to delete gdrive backup.

        Parameters:
    request (HttpRequest): The HTTP request object.

    Returns:
    GET : return gdrive backup setup template
    """
    if GoogleDriveBackup.objects.exists():
        gdrive_backup = GoogleDriveBackup.objects.first()
        gdrive_backup.delete()
        stop_gdrive_backup_job()
        messages.success(request, _("Gdrive Backup Automation Removed Successfully."))
    return redirect("gdrive")


@login_required
@permission_required("horilla_backup.change_googleldrivebackup")
def oauth_authorize(request):
    """Start OAuth authorization flow for Google Drive."""
    backup = GoogleDriveBackup.objects.first()
    if not backup:
        messages.error(request, "No Google Drive backup configuration found. Please configure it first.")
        return redirect("gdrive")
        
    if backup.auth_method != 'oauth':
        messages.error(request, "Authentication method is not set to OAuth. Please change it to OAuth first.")
        return redirect("gdrive")
    
    if not backup.oauth_client_id or not backup.oauth_client_secret:
        messages.error(request, "OAuth credentials not configured. Please add Client ID and Client Secret first.")
        return redirect("gdrive")
    
    if backup.oauth_refresh_token:
        messages.info(request, "OAuth is already authorized. Your Google Drive backup is ready to use.")
        return redirect("gdrive")
    
    try:
        from horilla_backup.gdrive import create_oauth_flow, get_oauth_authorization_url
        from django.conf import settings
        
        # Create OAuth flow with explicit HTTPS for production
        redirect_uri = request.build_absolute_uri('/backup/oauth-callback/')
        
        # Ensure HTTPS in production
        if not settings.DEBUG and redirect_uri.startswith('http://'):
            redirect_uri = redirect_uri.replace('http://', 'https://', 1)
            
        flow = create_oauth_flow(backup.oauth_client_id, backup.oauth_client_secret, redirect_uri)
        
        # Get authorization URL
        auth_url, state = get_oauth_authorization_url(flow)
        
        # Store state in session for verification
        request.session['oauth_state'] = state
        request.session['oauth_flow_data'] = {
            'client_id': backup.oauth_client_id,
            'client_secret': backup.oauth_client_secret,
            'redirect_uri': redirect_uri
        }
        
        return redirect(auth_url)
        
    except Exception as e:
        messages.error(request, f"OAuth authorization failed: {str(e)}")
        return redirect("gdrive")


@login_required  
@permission_required("horilla_backup.change_googleldrivebackup")
def oauth_callback(request):
    """Handle OAuth callback from Google."""
    code = request.GET.get('code')
    state = request.GET.get('state')
    error = request.GET.get('error')
    
    if error:
        messages.error(request, f"OAuth authorization failed: {error}")
        return redirect("gdrive")
    
    if not code:
        messages.error(request, "No authorization code received.")
        return redirect("gdrive")
    
    # Verify state
    if state != request.session.get('oauth_state'):
        messages.error(request, "OAuth state mismatch. Please try again.")
        return redirect("gdrive")
    
    try:
        from horilla_backup.gdrive import create_oauth_flow, exchange_oauth_code
        
        # Get flow data from session
        flow_data = request.session.get('oauth_flow_data')
        if not flow_data:
            messages.error(request, "OAuth session expired. Please try again.")
            return redirect("gdrive")
        
        # Recreate OAuth flow
        flow = create_oauth_flow(
            flow_data['client_id'], 
            flow_data['client_secret'], 
            flow_data['redirect_uri']
        )
        
        # Exchange code for tokens
        tokens = exchange_oauth_code(flow, code)
        
        # Save refresh token to backup configuration
        backup = GoogleDriveBackup.objects.first()
        backup.oauth_refresh_token = tokens['refresh_token']
        backup.save()
        
        # Clean up session
        request.session.pop('oauth_state', None)
        request.session.pop('oauth_flow_data', None)
        
        messages.success(request, "OAuth authorization successful! Google Drive backup is now configured.")
        return redirect("gdrive")
        
    except Exception as e:
        messages.error(request, f"OAuth callback failed: {str(e)}")
        return redirect("gdrive")
