from __future__ import annotations

import base64
import re
from typing import TYPE_CHECKING, Optional
from urllib.parse import urlparse

from mockmesh.interceptors.common import parse_request_body

if TYPE_CHECKING:
    from mockmesh.storage.manager import StorageManager


read_body = parse_request_body


def _bucket_key(req: dict) -> tuple[str, str]:
    url = req.get("url", "")
    try:
        p    = urlparse(url)
        host = p.hostname or ""
        m    = re.match(r"^(.+?)\.s3(?:\.[^.]+)*\.amazonaws\.com$", host)
        if m:
            return m.group(1), p.path.lstrip("/")
        parts = p.path.lstrip("/").split("/", 1)
        return (parts[0] if parts else ""), (parts[1] if len(parts) > 1 else "")
    except Exception:
        return "", ""


def handle_s3(sm: "StorageManager", req: dict, operation: str) -> Optional[dict]:
    bucket, key = _bucket_key(req)

    if operation == "PutObject":
        body = read_body(req)
        ct   = (req.get("headers") or {}).get("Content-Type", "application/octet-stream")
        r    = sm.s3_put(bucket, key, body, ct)
        return {"ETag": r["ETag"]}

    if operation == "GetObject" and key:
        obj = sm.s3_get(bucket, key)
        if obj:
            return {
                "Body":          base64.b64encode(obj["Body"]).decode(),
                "ContentType":   obj["ContentType"],
                "ContentLength": obj["ContentLength"],
                "ETag":          obj["ETag"],
            }

    if operation == "DeleteObject":
        sm.s3_delete(bucket, key)
        return {}

    if operation in ("ListObjectsV2", "ListObjects"):
        prefix = req.get("params", {}).get("Prefix") or ""
        objs   = sm.s3_list(bucket, prefix)
        return {"Contents": objs, "KeyCount": len(objs), "IsTruncated": False}

    if operation == "ListBuckets":
        buckets = [
            {"Name": b.removeprefix("s3-"), "CreationDate": "2024-01-01T00:00:00Z"}
            for b in sm.blob.list_buckets()
            if b.startswith("s3-")
        ]
        return {"Buckets": buckets, "Owner": {"DisplayName": "mock", "ID": "mock-id"}}

    if operation == "HeadObject":
        obj = sm.s3_get(bucket, key)
        if obj:
            return {
                "ContentLength": obj["ContentLength"],
                "ContentType":   obj["ContentType"],
                "ETag":          obj["ETag"],
                "LastModified":  "2024-01-01T00:00:00Z",
            }

    if operation == "CopyObject":
        copy_src = (
            req.get("headers", {}).get("x-amz-copy-source", "")
            or req.get("params", {}).get("CopySource", "")
        )
        if isinstance(copy_src, dict):
            src_bucket = copy_src.get("Bucket", bucket)
            src_key    = copy_src.get("Key", "")
        else:
            parts      = copy_src.lstrip("/").split("/", 1)
            src_bucket = parts[0] if parts else bucket
            src_key    = parts[1] if len(parts) > 1 else ""
        src_obj = sm.s3_get(src_bucket, src_key)
        if src_obj:
            sm.s3_put(bucket, key, src_obj["Body"], src_obj["ContentType"])
        return {"CopyObjectResult": {"ETag": '"mock-copy-etag"'}}

    return None
