"""Export formats for transcript data.

This module provides export functionality to common formats
for use with external tools like browser devtools.
"""

from __future__ import annotations

import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional


def export_to_har(
    http_records: List[Dict[str, Any]],
    creator_name: str = "AutoDebug",
    creator_version: str = "1.0",
) -> Dict[str, Any]:
    """Export HTTP records to HAR (HTTP Archive) format.

    HAR is a standard JSON format for recording HTTP transactions,
    supported by browser devtools and tools like Charles Proxy.

    Args:
        http_records: List of HTTP transcript records
        creator_name: Name of the tool creating this HAR
        creator_version: Version of the tool

    Returns:
        HAR-formatted dictionary
    """
    entries = []

    for record in http_records:
        if record.get("type") != "HTTP":
            continue

        # Parse timestamps
        started = record.get("ts") or record.get("timestamp")
        if isinstance(started, (int, float)):
            started_dt = datetime.fromtimestamp(started, tz=timezone.utc)
        else:
            started_dt = datetime.now(timezone.utc)

        # Build request headers
        request_headers = []
        for name, value in (record.get("request_headers") or {}).items():
            request_headers.append({"name": name, "value": str(value)})

        # Build response headers
        response_headers = []
        for name, value in (record.get("response_headers") or {}).items():
            response_headers.append({"name": name, "value": str(value)})

        # Calculate sizes
        request_body = record.get("request_body", "")
        response_body = record.get("response_body", "")
        request_body_size = len(request_body) if request_body else 0
        response_body_size = len(response_body) if response_body else 0

        # Determine content type
        content_type = ""
        for h in response_headers:
            if h["name"].lower() == "content-type":
                content_type = h["value"]
                break

        # Support both 'url' and 'url_canonical' field names
        url = record.get("url") or record.get("url_canonical", "")

        entry = {
            "startedDateTime": started_dt.isoformat(),
            "time": record.get("duration", 0) * 1000,  # HAR uses milliseconds
            "request": {
                "method": record.get("method", "GET"),
                "url": url,
                "httpVersion": "HTTP/1.1",
                "headers": request_headers,
                "queryString": _parse_query_string(url),
                "cookies": [],
                "headersSize": -1,
                "bodySize": request_body_size,
            },
            "response": {
                "status": record.get("status", 0),
                "statusText": _status_text(record.get("status", 0)),
                "httpVersion": "HTTP/1.1",
                "headers": response_headers,
                "cookies": [],
                "content": {
                    "size": response_body_size,
                    "mimeType": content_type or "application/octet-stream",
                    "text": response_body if isinstance(response_body, str) else "",
                },
                "redirectURL": "",
                "headersSize": -1,
                "bodySize": response_body_size,
            },
            "cache": {},
            "timings": {
                "send": 0,
                "wait": record.get("duration", 0) * 1000,
                "receive": 0,
            },
        }

        # Add request body if present
        if request_body:
            entry["request"]["postData"] = {
                "mimeType": _get_request_content_type(request_headers),
                "text": request_body if isinstance(request_body, str) else "",
            }

        entries.append(entry)

    return {
        "log": {
            "version": "1.2",
            "creator": {
                "name": creator_name,
                "version": creator_version,
            },
            "entries": entries,
        }
    }


def _parse_query_string(url: str) -> List[Dict[str, str]]:
    """Parse query string from URL into HAR format."""
    if "?" not in url:
        return []

    query_part = url.split("?", 1)[1]
    if "#" in query_part:
        query_part = query_part.split("#", 1)[0]

    result = []
    for pair in query_part.split("&"):
        if "=" in pair:
            name, value = pair.split("=", 1)
            result.append({"name": name, "value": value})
        else:
            result.append({"name": pair, "value": ""})

    return result


def _get_request_content_type(headers: List[Dict[str, str]]) -> str:
    """Get content-type from request headers."""
    for h in headers:
        if h["name"].lower() == "content-type":
            return h["value"]
    return "application/x-www-form-urlencoded"


def _status_text(status: int) -> str:
    """Get HTTP status text for status code."""
    status_texts = {
        200: "OK",
        201: "Created",
        204: "No Content",
        301: "Moved Permanently",
        302: "Found",
        304: "Not Modified",
        400: "Bad Request",
        401: "Unauthorized",
        403: "Forbidden",
        404: "Not Found",
        405: "Method Not Allowed",
        500: "Internal Server Error",
        502: "Bad Gateway",
        503: "Service Unavailable",
    }
    return status_texts.get(status, "Unknown")


def export_to_curl(http_records: List[Dict[str, Any]]) -> str:
    """Export HTTP records as curl commands.

    Args:
        http_records: List of HTTP transcript records

    Returns:
        String with curl commands, one per line
    """
    commands = []

    for record in http_records:
        if record.get("type") != "HTTP":
            continue

        parts = ["curl"]

        # Method
        method = record.get("method", "GET")
        if method != "GET":
            parts.append(f"-X {method}")

        # Headers
        for name, value in (record.get("request_headers") or {}).items():
            # Skip host header (derived from URL)
            if name.lower() == "host":
                continue
            # Escape quotes in value
            escaped_value = str(value).replace('"', '\\"')
            parts.append(f'-H "{name}: {escaped_value}"')

        # Request body
        body = record.get("request_body")
        if body:
            if isinstance(body, str):
                escaped_body = body.replace("'", "'\\''")
                parts.append(f"-d '{escaped_body}'")
            else:
                parts.append(f"-d '{json.dumps(body)}'")

        # URL - support both 'url' and 'url_canonical' field names
        url = record.get("url") or record.get("url_canonical", "")
        parts.append(f'"{url}"')

        commands.append(" \\\n  ".join(parts))

    return "\n\n".join(commands)


def export_to_postman(
    http_records: List[Dict[str, Any]],
    collection_name: str = "AutoDebug Export",
) -> Dict[str, Any]:
    """Export HTTP records to Postman Collection format (v2.1).

    Args:
        http_records: List of HTTP transcript records
        collection_name: Name for the Postman collection

    Returns:
        Postman Collection v2.1 formatted dictionary
    """
    items = []

    for i, record in enumerate(http_records):
        if record.get("type") != "HTTP":
            continue

        method = record.get("method", "GET")
        # Support both 'url' and 'url_canonical' field names
        url = record.get("url") or record.get("url_canonical", "")

        # Parse URL parts
        url_parts = _parse_url(url)

        # Build headers
        headers = []
        for name, value in (record.get("request_headers") or {}).items():
            headers.append({
                "key": name,
                "value": str(value),
                "type": "text",
            })

        item = {
            "name": f"{method} {url_parts['path'][:50]}",
            "request": {
                "method": method,
                "header": headers,
                "url": {
                    "raw": url,
                    "protocol": url_parts["protocol"],
                    "host": url_parts["host"].split("."),
                    "path": url_parts["path"].strip("/").split("/"),
                    "query": [
                        {"key": q["name"], "value": q["value"]}
                        for q in _parse_query_string(url)
                    ],
                },
            },
            "response": [],
        }

        # Add body if present
        body = record.get("request_body")
        if body:
            item["request"]["body"] = {
                "mode": "raw",
                "raw": body if isinstance(body, str) else json.dumps(body),
                "options": {
                    "raw": {
                        "language": "json" if _is_json(body) else "text",
                    }
                },
            }

        items.append(item)

    return {
        "info": {
            "name": collection_name,
            "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
        },
        "item": items,
    }


def _parse_url(url: str) -> Dict[str, str]:
    """Parse URL into components."""
    result = {
        "protocol": "https",
        "host": "",
        "path": "/",
    }

    if "://" in url:
        result["protocol"], rest = url.split("://", 1)
    else:
        rest = url

    if "/" in rest:
        result["host"], path = rest.split("/", 1)
        result["path"] = "/" + path.split("?")[0].split("#")[0]
    else:
        result["host"] = rest.split("?")[0].split("#")[0]

    return result


def _is_json(body: Any) -> bool:
    """Check if body appears to be JSON."""
    if isinstance(body, (dict, list)):
        return True
    if isinstance(body, str):
        try:
            json.loads(body)
            return True
        except (json.JSONDecodeError, ValueError):
            return False
    return False


def save_har(
    http_records: List[Dict[str, Any]],
    output_path: Path,
) -> None:
    """Save HTTP records as HAR file.

    Args:
        http_records: List of HTTP transcript records
        output_path: Path to write HAR file
    """
    har = export_to_har(http_records)
    output_path.write_text(json.dumps(har, indent=2), encoding="utf-8")


def save_postman(
    http_records: List[Dict[str, Any]],
    output_path: Path,
    collection_name: Optional[str] = None,
) -> None:
    """Save HTTP records as Postman collection.

    Args:
        http_records: List of HTTP transcript records
        output_path: Path to write Postman collection
        collection_name: Optional name for the collection
    """
    name = collection_name or output_path.stem
    collection = export_to_postman(http_records, collection_name=name)
    output_path.write_text(json.dumps(collection, indent=2), encoding="utf-8")
