import os
import subprocess
import datetime
import zipfile
import logging
from django.core.management.base import BaseCommand
from django.conf import settings

logger = logging.getLogger(__name__)

class Command(BaseCommand):
    help = 'Create a database backup and upload it to Google Drive'

    def handle(self, *args, **options):
        self.stdout.write(self.style.NOTICE("Starting database backup process..."))

        db_settings = settings.DATABASES['default']
        db_name = db_settings['NAME']
        db_user = db_settings['USER']
        db_password = db_settings['PASSWORD']
        db_host = db_settings['HOST']
        db_port = db_settings['PORT']

        timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_filename = f"{db_name}_backup_{timestamp}.sql"
        zip_filename = f"{backup_filename}.zip"
        
        backup_dir = os.path.join(settings.BASE_DIR, 'backups')
        os.makedirs(backup_dir, exist_ok=True)
        
        backup_path = os.path.join(backup_dir, backup_filename)
        zip_path = os.path.join(backup_dir, zip_filename)

        # Environment variables for pg_dump
        env = os.environ.copy()
        if db_password:
            env['PGPASSWORD'] = db_password

        # 1. Run pg_dump
        dump_cmd = [
            'pg_dump',
            '-U', db_user,
            '-h', db_host,
            '-p', str(db_port),
            '-F', 'c', # Custom format
            '-f', backup_path,
            db_name
        ]

        self.stdout.write(f"Executing pg_dump for database {db_name}...")
        try:
            # Note: in production, ensure pg_dump is in PATH
            subprocess.run(dump_cmd, env=env, check=True, capture_output=True)
            self.stdout.write(self.style.SUCCESS(f"Database dumped successfully to {backup_path}"))
        except FileNotFoundError:
            self.stderr.write(self.style.WARNING("pg_dump not found in PATH. Creating a dummy backup file for testing the upload flow..."))
            with open(backup_path, 'w') as f:
                f.write(f"-- Dummy backup for {db_name}\n-- pg_dump was not found locally.")
        except subprocess.CalledProcessError as e:
            self.stderr.write(self.style.ERROR(f"pg_dump failed: {e.stderr.decode()}"))
            return

        # 2. Compress the dump
        self.stdout.write("Compressing backup...")
        try:
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                zipf.write(backup_path, backup_filename)
            self.stdout.write(self.style.SUCCESS(f"Backup compressed to {zip_path}"))
            
            # Remove uncompressed file
            if os.path.exists(backup_path):
                os.remove(backup_path)
        except Exception as e:
            self.stderr.write(self.style.ERROR(f"Compression failed: {e}"))
            return

        # 3. Upload to Google Drive (if credentials exist)
        # Note: You must place 'gdrive_credentials.json' in the project root
        credentials_file = os.path.join(settings.BASE_DIR, 'gdrive_credentials.json')
        if os.path.exists(credentials_file):
            self.stdout.write("Uploading to Google Drive...")
            try:
                self.upload_to_gdrive(zip_path, zip_filename, credentials_file)
                self.stdout.write(self.style.SUCCESS("Backup successfully uploaded to Google Drive!"))
            except Exception as e:
                self.stderr.write(self.style.ERROR(f"Google Drive upload failed: {e}"))
        else:
            self.stdout.write(self.style.WARNING("Skipping Google Drive upload: gdrive_credentials.json not found."))
            self.stdout.write(self.style.NOTICE("To enable Drive uploads, set up a Service Account in GCP and place the JSON key at the project root."))

        self.stdout.write(self.style.SUCCESS("Backup process completed."))

    def upload_to_gdrive(self, file_path, file_name, credentials_file):
        """Uploads a file to Google Drive using a Service Account"""
        try:
            from google.oauth2 import service_account
            from googleapiclient.discovery import build
            from googleapiclient.http import MediaFileUpload
        except ImportError:
            self.stderr.write(self.style.ERROR("Google API libraries not installed. Run: pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib"))
            raise Exception("Missing googleapiclient")

        SCOPES = ['https://www.googleapis.com/auth/drive.file']
        creds = service_account.Credentials.from_service_account_file(
            credentials_file, scopes=SCOPES)

        service = build('drive', 'v3', credentials=creds)

        file_metadata = {'name': file_name}
        media = MediaFileUpload(file_path, mimetype='application/zip')

        # To upload to a specific folder, add 'parents': ['FOLDER_ID'] to file_metadata
        from decouple import config
        folder_id = config('GDRIVE_BACKUP_FOLDER_ID', default='')
        if folder_id:
            file_metadata['parents'] = [folder_id]

        file = service.files().create(body=file_metadata,
                                      media_body=media,
                                      fields='id',
                                      supportsAllDrives=True).execute()
        
        return file.get('id')
