#!/usr/bin/env python3

import logging
import os

import requests
from requests.auth import HTTPBasicAuth

from app.celery_app import celery
from app.config import settings
from app.tasks.retry_config import UploadTaskWithRetry
from app.utils import log_task_progress
from app.utils.filename_utils import extract_remote_path, get_unique_filename

logger = logging.getLogger(__name__)


@celery.task(base=UploadTaskWithRetry, bind=True)
def upload_to_nextcloud(self, file_path: str, file_id: int = None, folder_override: str = None):
    """
    Upload a file to Nextcloud WebDAV.

    Args:
        file_path: Path to the file to upload
        file_id: Optional file ID to associate with logs
    """
    task_id = self.request.id
    logger.info(f"[{task_id}] Starting Nextcloud upload: {file_path}")
    log_task_progress(
        task_id,
        "upload_to_nextcloud",
        "in_progress",
        f"Uploading to Nextcloud: {os.path.basename(file_path)}",
        file_id=file_id,
    )

    if not os.path.exists(file_path):
        error_msg = f"File not found: {file_path}"
        logger.error(f"[{task_id}] {error_msg}")
        log_task_progress(task_id, "upload_to_nextcloud", "failure", error_msg, file_id=file_id)
        raise FileNotFoundError(error_msg)

    # For Nextcloud, we need to check for 'nextcloud_upload_url' instead of 'nextcloud_url'
    # This is what's shown in your env view
    if not (
        getattr(settings, "nextcloud_upload_url", None)
        and getattr(settings, "nextcloud_username", None)
        and getattr(settings, "nextcloud_password", None)
    ):
        logger.info(f"[{task_id}] Nextcloud upload skipped: Missing configuration")
        log_task_progress(task_id, "upload_to_nextcloud", "success", "Skipped: Not configured", file_id=file_id)
        return {"status": "Skipped", "reason": "Nextcloud settings not configured"}

    filename = os.path.basename(file_path)

    try:
        # Prepare WebDAV URL - use nextcloud_upload_url instead of nextcloud_url
        webdav_url = settings.nextcloud_upload_url
        if not webdav_url.endswith("/"):
            webdav_url += "/"

        # Calculate remote path based on local file structure
        remote_base = (
            folder_override if folder_override is not None else (getattr(settings, "nextcloud_folder", "") or "")
        )
        remote_path = extract_remote_path(file_path, settings.workdir, remote_base)
        full_url = f"{webdav_url}/{remote_path}"

        # Remove any double slashes (except in http://)
        full_url = full_url.replace("://", "$PLACEHOLDER$")
        while "//" in full_url:
            full_url = full_url.replace("//", "/")
        full_url = full_url.replace("$PLACEHOLDER$", "://")

        # Function to check if file exists in Nextcloud
        def check_exists_in_nextcloud(path):
            check_url = f"{webdav_url}{os.path.dirname(path)}"
            try:
                response = requests.request(
                    "PROPFIND",
                    check_url,
                    auth=HTTPBasicAuth(settings.nextcloud_username, settings.nextcloud_password),
                    headers={"Depth": "1"},
                    timeout=10,
                )

                return path in response.text
            except Exception:
                # If we can't check, assume it doesn't exist
                return False

        # Check for potential file collision and get a unique name if needed
        remote_path = get_unique_filename(remote_path, check_exists_in_nextcloud)
        full_url = f"{webdav_url}/{remote_path}"

        # Fix double slashes again
        full_url = full_url.replace("://", "$PLACEHOLDER$")
        while "//" in full_url:
            full_url = full_url.replace("//", "/")
        full_url = full_url.replace("$PLACEHOLDER$", "://")

        # Create necessary parent folders
        parent_dirs = os.path.dirname(remote_path)
        if parent_dirs:
            current_path = ""
            for folder in parent_dirs.split("/"):
                if not folder:
                    continue
                current_path += f"{folder}/"
                mkdir_url = f"{webdav_url}/{current_path}"
                # Fix double slashes
                mkdir_url = mkdir_url.replace("://", "$PLACEHOLDER$")
                while "//" in mkdir_url:
                    mkdir_url = mkdir_url.replace("//", "/")
                mkdir_url = mkdir_url.replace("$PLACEHOLDER$", "://")

                requests.request(
                    "MKCOL",
                    mkdir_url,
                    auth=HTTPBasicAuth(settings.nextcloud_username, settings.nextcloud_password),
                    timeout=10,
                )

        # Upload the file
        logger.info(f"[{task_id}] Uploading {filename} to Nextcloud at {full_url}")
        log_task_progress(task_id, "upload_file", "in_progress", f"Uploading to {remote_path}", file_id=file_id)
        with open(file_path, "rb") as file_data:
            response = requests.put(
                full_url,
                data=file_data,
                auth=HTTPBasicAuth(settings.nextcloud_username, settings.nextcloud_password),
                headers={"Content-Type": "application/octet-stream"},
                timeout=settings.http_request_timeout,  # Use configured timeout for large files
            )

        if response.status_code in (201, 204):  # Created or No Content
            logger.info(f"[{task_id}] Successfully uploaded {filename} to Nextcloud at {remote_path}")
            log_task_progress(
                task_id, "upload_to_nextcloud", "success", f"Uploaded to Nextcloud: {remote_path}", file_id=file_id
            )
            return {
                "status": "Completed",
                "file_path": file_path,
                "nextcloud_path": remote_path,
                "response_code": response.status_code,
            }
        else:
            error_msg = f"Failed to upload {filename} to Nextcloud: {response.status_code} - {response.text}"
            logger.error(f"[{task_id}] {error_msg}")
            log_task_progress(task_id, "upload_to_nextcloud", "failure", error_msg, file_id=file_id)
            raise Exception(error_msg)

    except Exception as e:
        error_msg = f"Failed to upload {filename} to Nextcloud: {str(e)}"
        logger.error(f"[{task_id}] {error_msg}")
        log_task_progress(task_id, "upload_to_nextcloud", "failure", error_msg, file_id=file_id)
        raise Exception(error_msg)
