"""
Customer Attachments Services - Handle customer file attachments
"""

from typing import List, Dict
import logging
from fastapi import status, UploadFile
from sqlalchemy import select, delete
from sqlalchemy.orm import Session

from src.apps.customers.models.customer import customer_attachments_map
from src.apps.customers.services.customer_services import get_customer
from src.apps.files.models.file import File
from src.apps.files.file_services import _create_file_database_entry
from src.apps.files.helper.io import remove_file_single, upload_file_single
from src.apps.files.schemas.file_common import FileResponseSchema
from src.apps.users.schemas.user_common import UserSchema
from src.apps.merchants.schemas.merchant_common import MerchantSchema
from src.core.utils.constants import ALLOWED_FILE_CONTENT_TYPES, MAX_UPLOAD_LIMIT
from src.core.exceptions import APIException
from src.core.config import settings
from src.apps.files.helper.io import get_physical_filesize

logger = logging.getLogger(__name__)


async def upload_customer_attachments(
    db: Session,
    files: List[UploadFile],
    file_type: str,
    current_user: UserSchema,
    merchant: MerchantSchema,
    customer_id: str,
) -> List[FileResponseSchema]:
    """
    Upload multiple attachment files for a customer.
    Files are stored in: uploads/data_files/merchant_id/accounts/customer_id/
    """

    if len(files) > MAX_UPLOAD_LIMIT:
        msg = f"A maximum of {MAX_UPLOAD_LIMIT} files can be uploaded at once"
        raise APIException(
            module=__name__,
            error={},
            status_code=status.HTTP_400_BAD_REQUEST,
            message=msg
        )

    # Validate content types
    for f in files:
        extension = f.content_type.split("/")[1]
        if extension not in ALLOWED_FILE_CONTENT_TYPES:
            msg = (
                f"Cannot upload {extension} files. Allowed file extensions are "
                f"{', '.join(ALLOWED_FILE_CONTENT_TYPES)}"
            )
            raise APIException(
                module=__name__,
                error={},
                status_code=status.HTTP_400_BAD_REQUEST,
                message=msg
            )

    # Validate customer exists
    customer_data = await get_customer(db=db, customer_id=customer_id)
    
    # Upload files and create database entries
    upload_path = f"data_files/{merchant.merchant_id}/accounts/{customer_id}/"
    new_files = []
    
    for file in files:
        contents = file.file.read()
        uploaded_file_data = upload_file_single(db=db, file=file, contents=contents, path=upload_path)
        
        # Create database entry using shared file service function
        file_entry = await _create_file_database_entry(
            db=db,
            file_data=uploaded_file_data,
            file_type=file_type,
            created_by=current_user
        )
        # Get the path from the uploaded_file_data to construct full URL
        file_entry.full_url = f"{settings.SERVER_HOST}/uploads{uploaded_file_data['path']}"
        new_files.append(file_entry)
    
    if not new_files:
        raise APIException(
            module=__name__,
            error={},
            status_code=status.HTTP_400_BAD_REQUEST,
            message="Failed to upload files"
        )

    # Map newly created files to customer
    for file_data in new_files:
        map_statement = customer_attachments_map.insert().values(
            file_id=file_data.id,
            customer_id=customer_data.id
        )
        db.execute(map_statement)
    db.commit()

    logger.info(
        "Customer attachments uploaded successfully",
        extra={
            "app_module": "customer",
            "submodule": "attachments",
            "merchant_id": merchant.merchant_id,
            "customer_id": customer_id,
            "file_count": len(new_files),
            "created_by_id": current_user.user_id,
        },
    )
    
    return new_files


async def delete_customer_attachment(
    db: Session,
    customer_id: str,
    merchant: MerchantSchema,
    current_user: UserSchema,
    file_id: int,
) -> Dict:
    """Delete a customer's attachment file."""
    customer_data = await get_customer(db=db, customer_id=customer_id)

    file_data = db.execute(select(File).where(File.id == file_id)).scalar_one_or_none()
    
    if file_data is None:
        raise APIException(
            module=__name__,
            error={},
            status_code=status.HTTP_404_NOT_FOUND,
            message="The requested file was not found",
        )

    # Remove mapping and delete file
    db.execute(customer_attachments_map.delete().where(
        customer_attachments_map.c.file_id == file_id,
        customer_attachments_map.c.customer_id == customer_data.id,
    ))
    
    remove_file_single(path=file_data.upload_path)
    db.execute(delete(File).where(File.id == file_id))
    db.commit()

    logger.info(
        "Customer attachment deleted successfully",
        extra={
            "app_module": "customer",
            "submodule": "attachments",
            "merchant_id": merchant.merchant_id,
            "customer_id": customer_id,
            "file_id": file_id,
            "created_by_id": current_user.user_id,
        },
    )
    
    return {
        "success": True,
        "message": "Customer attachment deleted successfully"
    }


async def get_customer_attachments(
    db: Session,
    customer_id: str,
) -> List[FileResponseSchema]:
    """Get all attachments for a customer."""
    
    customer_data = await get_customer(db=db, customer_id=customer_id)
    
    attachments = db.execute(
        select(File)
        .join(customer_attachments_map, customer_attachments_map.c.file_id == File.id)
        .where(customer_attachments_map.c.customer_id == customer_data.id)
        .order_by(File.created_at.desc())
    ).scalars().all()
    
    response_list = []
    for file_obj in attachments:
        result = FileResponseSchema.model_validate(file_obj)
        result.filesize = get_physical_filesize(file_obj.path)
        # Use the model's path attribute before it's converted to schema
        result.full_url = f"{settings.SERVER_HOST}/uploads{file_obj.path}"
        response_list.append(result)
    
    return response_list
