import logging
import os

from .utils import build_s3_key, generate_uuid, sanitize_filename
from .models import UploadResult

logger = logging.getLogger(__name__)


class DocumentStorage:

    def __init__(self, s3_client, repository, config):
        self.s3 = s3_client
        self.repo = repository
        self.config = config

    def upload_file(self, file_obj, request):
        file_uuid = generate_uuid()
        key = build_s3_key(request, file_uuid)

        try:
            logger.info(f"Uploading file {request.file_name} to S3 key {key}")

            # 1. Upload to S3
            response = self.s3.upload(key, file_obj)

            # =========================
            # 🔥 CRITICAL: derive metadata properly
            # =========================
            safe_name = sanitize_filename(request.file_name)
            file_extension = os.path.splitext(request.file_name)[1].replace(".", "")

            etag = response.get("ETag", "").strip('"')
            version_id = response.get("VersionId")

            logger.info(f"Saving metadata for {key} in MySQL")

            # 2. Save metadata in DB
            self.repo.insert({
                "tenant_name": request.tenant_name,
                "clinic_id": request.clinic_id,
                "patient_id": request.patient_id,
                "bucket": self.config.bucket,
                "key": key,
                "version_id": version_id,
                "document_type": request.document_type,
                "document_format": request.document_format,
                "file_name": request.file_name,
                "file_name_safe": safe_name,
                "file_extension": file_extension,
                "content_type": request.content_type,
                "size": request.content_length,
                "review_status": request.review_status,
                "etag": etag,
                "custom_metadata": request.custom_metadata
            })

            return UploadResult(
                bucket=self.config.bucket,
                key=key,
                etag=etag,
                version_id=version_id,
            )

        except Exception as e:
            logger.error(f"Error during upload sequence for {key}: {str(e)}")

            # rollback S3 if DB fails
            try:
                if self.s3.exists(key):
                    logger.info(f"Rolling back S3 upload, deleting key {key}")
                    self.s3.delete(key)
            except Exception as rollback_e:
                logger.error(f"Failed to rollback S3 key {key}: {str(rollback_e)}")

            raise e

    def download_file(self, object_ref):
        return self.s3.download(object_ref.key)

    def generate_view_url(self, object_ref):
        return self.s3.generate_url(
            object_ref.key,
            self.config.presigned_expiry
        )

    def delete_document(self, object_ref, hard_delete=False):
        if hard_delete:
            self.s3.delete(object_ref.key)

        self.repo.soft_delete(object_ref.bucket, object_ref.key)

    def document_exists(self, object_ref):
        db_record = self.repo.get_by_key(object_ref.bucket, object_ref.key)
        return db_record is not None

    def list_documents(self, tenant_name, patient_id=None):
        logger.info(f"Listing documents for tenant {tenant_name}, patient {patient_id}")
        return self.repo.list_documents(tenant_name, patient_id)