import datetime
import os
from typing import Optional

from fastapi import HTTPException, UploadFile, status
from sqlalchemy.orm import Session

from src.apps.files.models.cdn import CDN
from src.apps.files.models.file import File
from src.apps.files.schemas.file import (
    FileCreateSchema,
    FileResponseSchema,
    FileUpdateSchema,
)
from src.utils.pagination import QueryPaginator

FILE_UPLOAD_DIR = "uploads/files"  # Or any path where you want to store
CRAWLER_FILE_UPLOAD_DIR = "uploads/match_outputs"  # Or any path where you want to store
CRAWLER_FILE_UPLOAD_HISTORY_DIR = "uploads/history"  # Directory for historical files

# Ensure upload directory exists
os.makedirs(FILE_UPLOAD_DIR, exist_ok=True)
os.makedirs(CRAWLER_FILE_UPLOAD_DIR, exist_ok=True)
os.makedirs(CRAWLER_FILE_UPLOAD_HISTORY_DIR, exist_ok=True)


async def create_file(
    db: Session,
    upload_file: UploadFile,
    is_history: bool = False,
    created_by_id: Optional[int] = None,
    name: Optional[str] = None,
    is_crawler: Optional[bool] = False,
) -> File:
    """
    Create a File record and save the actual uploaded file.
    """
    # Use original filename as original_name
    original_name = upload_file.filename

    new_file_name = f"{original_name}"

    if not is_crawler:
        file_path = os.path.join(FILE_UPLOAD_DIR, new_file_name).replace("\\", "/")
    else:
        if is_history:
            file_path = os.path.join(CRAWLER_FILE_UPLOAD_HISTORY_DIR, new_file_name).replace("\\", "/")
        else:
            file_path = os.path.join(CRAWLER_FILE_UPLOAD_DIR, new_file_name).replace("\\", "/")
        # Save file content to disk
        full_path = os.path.abspath(file_path)
        with open(full_path, "wb") as f:
            content = await upload_file.read()
            f.write(content)

        # Get MIME type from upload
        mime = upload_file.content_type

        cdn = db.query(CDN).filter(CDN.is_active == True).first()
        if not cdn:
            raise HTTPException(status_code=404, detail="CDN with label 'Crawler Files CDN' not found")

        new_file = File(
            original_name=original_name,
            name=new_file_name,
            path=file_path,
            mime=mime,
            created_by_id=created_by_id,
            cdn_id=cdn.id,
        )

        db.add(new_file)
        db.commit()
        db.refresh(new_file)

        return new_file


def get_file(db: Session, file_id: int) -> File:
    """
    Retrieve a file by ID.
    """
    file = db.query(File).filter(File.id == file_id).first()
    if not file:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found")
    return file


def get_all_files(db: Session, page: int = 1, per_page: int = 10):
    """
    Retrieve a paginated list of files.

    :param db: SQLAlchemy Session
    :param page: Page number (default: 1)
    :param per_page: Items per page (default: 10)
    :return: Paginated files response
    """
    offset = (page - 1) * per_page
    query = db.query(File)

    paginator = QueryPaginator(
        query=query,
        schema=FileResponseSchema,
        url="/files",  # Adjust URL as needed for OpenAPI links
        offset=offset,
        limit=per_page,
        use_orm=True,
    )
    return paginator.paginate()


def get_file_by_id(db: Session, file_id: int) -> File:
    """
    Retrieve a File by its ID.
    """
    file_obj = db.query(File).filter(File.id == file_id).first()
    if not file_obj:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found")
    return file_obj


def update_file(db: Session, file_id: int, payload: FileUpdateSchema) -> File:
    """
    Update an existing file.
    """
    file = get_file(db, file_id)

    for field, value in payload.dict(exclude_unset=True).items():
        setattr(file, field, value)

    db.commit()
    db.refresh(file)
    return file


def delete_file(db: Session, file_id: int) -> None:
    """
    Delete a file by its ID.

    :param db: SQLAlchemy Session
    :param file_id: ID of the file to delete
    :raises HTTPException: if file not found
    """

    file_obj = db.query(File).filter(File.id == file_id).first()

    if not file_obj:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found")

    db.delete(file_obj)
    db.commit()
