from dataclasses import replace
from src.domain.connectors.catalog._object_store import object_actions

from src.domain.connectors.catalog._base import (
    ConnectorActionDef,
    ConnectorChangelogEntry,
    ConnectorDef,
    ConnectorFieldDef,
)


CONNECTOR = ConnectorDef(
    key="cloudflare_r2",
    name="Cloudflare R2",
    category="storage",
    auth_type="api_key",
    version="01.06.00",
    status="preview",
    icon="cloud",
    image_url=None,  # set to your CDN URL
    description="Connect to your own Cloudflare R2 account. You must supply your account ID, R2 S3 API keys (access key + secret), and a Cloudflare account API token. Credentials are encrypted per project and never use platform-owned keys.",
    docs_url="https://developers.cloudflare.com/r2/",
    config_fields=("account_id", "path_prefix", "public_url_base", "bucket_name", "storage_map"),
    secret_fields=("access_key_id", "secret_access_key", "cloudflare_api_token",),
    config_field_defs=(
        ConnectorFieldDef(key="storage_map", label="Storage bindings", input_type="json",
                          description='JSON object: alias -> {"bucket_name": "...", "prefix": "..."}'),
        ConnectorFieldDef(
            key="account_id",
            label="Cloudflare account ID",
            description="Your Cloudflare account — Dashboard -> Account Home.",
            required=True,
        ),
        ConnectorFieldDef(
            key="bucket_name",
            label="Default bucket",
            description="Optional default bucket name.",
        ),
        ConnectorFieldDef(
            key="path_prefix",
            label="Path prefix",
            description="Optional folder prefix for object keys.",
        ),
        ConnectorFieldDef(
            key="public_url_base",
            label="Public URL base",
            description="Optional CDN or r2.dev base URL for public buckets.",
            input_type="url",
        ),
    ),
    secret_field_defs=(
        ConnectorFieldDef(
            key="access_key_id",
            label="R2 access key ID (S3 API)",
            description="From R2 -> Manage R2 API Tokens in your Cloudflare account.",
            required=True,
            input_type="password",
        ),
        ConnectorFieldDef(
            key="secret_access_key",
            label="R2 secret access key (S3 API)",
            description="Shown once when you create the R2 API token.",
            required=True,
            input_type="password",
        ),
        ConnectorFieldDef(
            key="cloudflare_api_token",
            label="Cloudflare account API token",
            description="My Profile -> API Tokens, with Account / R2 permissions.",
            required=True,
            input_type="password",
        ),
    ),
    actions=(
        ConnectorActionDef(
            key="list_buckets",
            slug="cloudflare_r2.list_buckets",
            name="List buckets",
            description="List all R2 buckets visible to the connection credentials.",
            input_schema={"type": "object", "properties": {}},
            output_schema={
                "type": "object",
                "properties": {
                    "buckets": {"type": "array"},
                    "bucket_count": {"type": "integer"},
                    "list_access": {"type": "string"},
                    "warning": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="create_bucket",
            slug="cloudflare_r2.create_bucket",
            name="Create bucket",
            description="Create a new R2 bucket. Public access enables the r2.dev domain via Cloudflare API (requires cloudflare_api_token on the connection).",
            input_schema={
                "type": "object",
                "required": ["bucket_name"],
                "properties": {
                    "bucket_name": {"type": "string"},
                    "access_type": {"type": "string", "enum": ["public", "private"]},
                    "cloudflare_api_token": {
                        "type": "string",
                        "description": "Optional override for public access (else uses connection secret)",
                    },
                    "browser_origin": {
                        "type": "string",
                        "description": "Dashboard origin (e.g. https://dashboard.p2hs.com) — auto-adds bucket CORS when API token is available",
                    },
                    "browser_origins": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Additional allowed browser origins for bucket CORS",
                    },
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "bucket_name": {"type": "string"},
                    "created": {"type": "boolean"},
                    "verified": {"type": "boolean"},
                    "already_exists": {"type": "boolean"},
                    "access_type": {"type": "string"},
                    "public_access_enabled": {"type": "boolean"},
                    "public_url": {"type": "string"},
                    "cors_updated": {"type": "boolean"},
                    "cors_origins": {"type": "array", "items": {"type": "string"}},
                    "note": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="list_objects",
            slug="cloudflare_r2.list_objects",
            name="List objects",
            description="List one page of objects in a bucket (S3 ListObjectsV2 cursor pagination).",
            input_schema={
                "type": "object",
                "properties": {
                    "bucket_name": {
                        "type": "string",
                        "description": "Target bucket (falls back to connection default)",
                    },
                    "prefix": {"type": "string", "description": "Key prefix filter"},
                    "max_keys": {"type": "integer", "description": "Page size (1–1000, default 100)"},
                    "continuation_token": {
                        "type": "string",
                        "description": "Pagination cursor from previous page",
                    },
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "bucket_name": {"type": "string"},
                    "objects": {"type": "array"},
                    "key_count": {"type": "integer"},
                    "truncated": {"type": "boolean"},
                    "next_continuation_token": {"type": "string"},
                    "max_keys": {"type": "integer"},
                },
            },
        ),
        ConnectorActionDef(
            key="presign_put",
            slug="cloudflare_r2.presign_put",
            name="Generate upload URL",
            description="Generate a presigned PUT URL for direct browser uploads. When browser_origin is sent, bucket CORS is auto-configured via Cloudflare API (requires cloudflare_api_token on the connection).",
            input_schema={
                "type": "object",
                "required": ["key"],
                "properties": {
                    "key": {"type": "string", "description": "Object key (path within bucket)"},
                    "content_type": {
                        "type": "string",
                        "description": "MIME type of the file being uploaded",
                    },
                    "expires_in": {
                        "type": "integer",
                        "description": "URL validity in seconds (default 3600, max 86400). Browser uploads should use at least 3600; large files may need up to 86400.",
                    },
                    "browser_origin": {
                        "type": "string",
                        "description": "Calling page origin — merged into bucket CORS before presigning",
                    },
                    "browser_origins": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Additional browser origins to allow on the bucket",
                    },
                    "cloudflare_api_token": {
                        "type": "string",
                        "description": "Optional override for CORS setup (else uses connection secret)",
                    },
                    "skip_cors_ensure": {
                        "type": "boolean",
                        "description": "Skip bucket CORS auto-config when already applied for this origin",
                    },
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "upload_url": {"type": "string"},
                    "key": {"type": "string"},
                    "expires_at": {"type": "string"},
                    "content_type": {"type": "string"},
                    "cors_updated": {"type": "boolean"},
                    "cors_origins": {"type": "array", "items": {"type": "string"}},
                },
            },
        ),
        ConnectorActionDef(
            key="presign_get",
            slug="cloudflare_r2.presign_get",
            name="Generate download URL",
            description="Returns a stable public URL when public_url_base is configured on the connection (or public_url_base is passed per request); otherwise a presigned GET URL.",
            input_schema={
                "type": "object",
                "required": ["key"],
                "properties": {
                    "key": {"type": "string"},
                    "expires_in": {
                        "type": "integer",
                        "description": "URL validity in seconds (default 3600)",
                    },
                    "public_url_base": {"type": "string", "description": "Per-request public base override"},
                    "force_presign": {"type": "boolean"},
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "download_url": {"type": "string"},
                    "key": {"type": "string"},
                    "url_type": {"type": "string"},
                    "expires_at": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="delete_object",
            slug="cloudflare_r2.delete_object",
            name="Delete object",
            description="Permanently delete an object from R2.",
            input_schema={
                "type": "object",
                "required": ["key"],
                "properties": {"key": {"type": "string"}},
            },
            output_schema={
                "type": "object",
                "properties": {"deleted": {"type": "boolean"}, "key": {"type": "string"}},
            },
        ),
        ConnectorActionDef(
            key="import_from_url",
            slug="cloudflare_r2.import_from_url",
            name="Import from URL",
            description="Download from URL into an archive bucket/key. Small zips extract inline; large zips queue batched extract_zip jobs. Supports separate extract bucket/prefix.",
            input_schema={
                "type": "object",
                "required": ["url", "key"],
                "properties": {
                    "url": {"type": "string", "description": "HTTP(S) URL to download"},
                    "key": {
                        "type": "string",
                        "description": "Archive object key (zip path in archive bucket)",
                    },
                    "bucket_name": {"type": "string", "description": "Archive bucket (alias)"},
                    "archive_bucket_name": {"type": "string"},
                    "extract_bucket_name": {"type": "string"},
                    "extract_prefix": {"type": "string"},
                    "content_type": {"type": "string"},
                    "extract_archive": {"type": "boolean"},
                    "delete_archive_after_extract": {"type": "boolean"},
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "key": {"type": "string"},
                    "size_bytes": {"type": "integer"},
                    "extracted": {"type": "boolean"},
                    "extract_deferred": {"type": "boolean"},
                    "extract_mode": {"type": "string"},
                    "archive_bucket": {"type": "string"},
                    "archive_key": {"type": "string"},
                    "extract_bucket": {"type": "string"},
                    "extract_prefix": {"type": "string"},
                    "chained_job_id": {"type": "string"},
                    "uploaded_count": {"type": "integer"},
                    "files": {"type": "array"},
                },
            },
        ),
        ConnectorActionDef(
            key="extract_zip",
            slug="cloudflare_r2.extract_zip",
            name="Extract zip from R2",
            description="Batched zip extraction from an object in one bucket into another bucket/prefix. Chains automatically for large archives.",
            input_schema={
                "type": "object",
                "required": ["source_bucket_name", "source_key", "extract_bucket_name"],
                "properties": {
                    "source_bucket_name": {"type": "string"},
                    "source_key": {"type": "string"},
                    "extract_bucket_name": {"type": "string"},
                    "extract_prefix": {
                        "type": "string",
                        "description": "Folder prefix; empty or / extracts to bucket root using zip paths",
                    },
                    "entry_offset": {"type": "integer"},
                    "entry_limit": {"type": "integer"},
                    "archive_size_bytes": {"type": "integer"},
                    "delete_archive_after": {"type": "boolean"},
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "extract_complete": {"type": "boolean"},
                    "total_entries": {"type": "integer"},
                    "next_offset": {"type": "integer"},
                    "chained_job_id": {"type": "string"},
                    "uploaded_count": {"type": "integer"},
                    "skipped_count": {"type": "integer"},
                    "first_write_error": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="head_object",
            slug="cloudflare_r2.head_object",
            name="Check object",
            description="Check whether an object exists and retrieve its size, content-type, and ETag.",
            input_schema={
                "type": "object",
                "required": ["key"],
                "properties": {"key": {"type": "string"}},
            },
            output_schema={
                "type": "object",
                "properties": {
                    "exists": {"type": "boolean"},
                    "key": {"type": "string"},
                    "size": {"type": "integer"},
                    "content_type": {"type": "string"},
                    "last_modified": {"type": "string"},
                    "etag": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="bulk_export",
            slug="cloudflare_r2.bulk_export",
            name="Bulk export",
            description="Export selected objects as CSV, Excel, text, Word, printable HTML (PDF), or a ZIP of file contents. Manifest formats include name and download URL per row.",
            input_schema={
                "type": "object",
                "required": ["format", "keys"],
                "properties": {
                    "format": {
                        "type": "string",
                        "enum": ["csv", "excel", "txt", "doc", "pdf", "zip"],
                    },
                    "keys": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Object keys (up to 200)",
                    },
                    "items": {
                        "type": "array",
                        "description": "Optional metadata from list (key, name, size, last_modified)",
                    },
                    "bucket_title": {"type": "string"},
                    "public_url_base": {
                        "type": "string",
                        "description": "Public CDN or r2.dev base — manifest URLs stay public (no presign)",
                    },
                    "force_presign": {
                        "type": "boolean",
                        "description": "Always presign manifest URLs even when public_url_base is set",
                    },
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "format": {"type": "string"},
                    "filename": {"type": "string"},
                    "content_type": {"type": "string"},
                    "content_base64": {"type": "string"},
                    "download_url": {"type": "string"},
                    "file_count": {"type": "integer"},
                    "row_count": {"type": "integer"},
                    "print_pdf": {"type": "boolean"},
                },
            },
        ),
        ConnectorActionDef(
            key="bulk_export_bucket",
            slug="cloudflare_r2.bulk_export_bucket",
            name="Export entire bucket (paginated)",
            description="List all objects in a bucket (optional prefix filter) and export as a manifest or batched ZIP archives. Use when the UI cannot select every page at once.",
            input_schema={
                "type": "object",
                "required": ["format"],
                "properties": {
                    "format": {
                        "type": "string",
                        "enum": ["csv", "excel", "txt", "doc", "pdf", "zip"],
                    },
                    "bucket_name": {
                        "type": "string",
                        "description": "Target bucket (falls back to connection default)",
                    },
                    "prefix": {"type": "string", "description": "Only export keys under this prefix"},
                    "max_objects": {"type": "integer", "description": "Safety cap (default 10000)"},
                    "bucket_title": {"type": "string"},
                    "public_url_base": {
                        "type": "string",
                        "description": "Public CDN or r2.dev base — manifest URLs stay public (no presign)",
                    },
                    "force_presign": {
                        "type": "boolean",
                        "description": "Always presign manifest URLs even when public_url_base is set",
                    },
                    "root_job_id": {
                        "type": "string",
                        "description": "Internal — root job id for chained bucket export batches",
                    },
                    "object_offset": {
                        "type": "integer",
                        "description": "Internal — manifest row batch offset",
                    },
                    "zip_key_offset": {
                        "type": "integer",
                        "description": "Internal — ZIP object key offset for chained batches",
                    },
                    "export_phase": {
                        "type": "string",
                        "enum": ["list", "manifest", "zip"],
                        "description": "Internal — chained bucket export phase",
                    },
                    "list_cursor": {
                        "type": "string",
                        "description": "Internal — pagination cursor for bucket listing",
                    },
                    "list_via": {
                        "type": "string",
                        "enum": ["cf", "s3"],
                        "description": "Internal — listing API used for continuation pages",
                    },
                },
            },
            output_schema={
                "type": "object",
                "properties": {
                    "format": {"type": "string"},
                    "filename": {"type": "string"},
                    "content_type": {"type": "string"},
                    "content_base64": {"type": "string"},
                    "download_url": {"type": "string"},
                    "row_count": {"type": "integer"},
                    "object_count": {"type": "integer"},
                    "file_count": {"type": "integer"},
                    "part_count": {"type": "integer"},
                    "zip_parts": {"type": "array"},
                    "skipped_keys": {"type": "array"},
                    "print_pdf": {"type": "boolean"},
                    "export_complete": {"type": "boolean"},
                    "chained_job_id": {"type": "string"},
                    "processed": {"type": "integer"},
                    "total": {"type": "integer"},
                    "phase": {"type": "string"},
                    "chain_error": {"type": "string"},
                },
            },
        ),
        ConnectorActionDef(
            key="bulk_delete",
            slug="cloudflare_r2.bulk_delete",
            name="Bulk delete",
            description="Delete up to 200 objects from the bucket in one job.",
            input_schema={
                "type": "object",
                "required": ["keys"],
                "properties": {"keys": {"type": "array", "items": {"type": "string"}}},
            },
            output_schema={
                "type": "object",
                "properties": {
                    "deleted_count": {"type": "integer"},
                    "failed_count": {"type": "integer"},
                    "deleted_keys": {"type": "array"},
                    "failed": {"type": "array"},
                },
            },
        ),
    ),
    changelog=(
        ConnectorChangelogEntry(
            version="01.00.00",
            date="2026-06-03",
            notes="Initial release: list_objects, presign_put, presign_get, delete_object, head_object.",
        ),
        ConnectorChangelogEntry(
            version="01.01.00",
            date="2026-06-02",
            notes="Added bulk_export and bulk_delete for multi-object export and deletion.",
        ),
        ConnectorChangelogEntry(
            version="01.02.00",
            date="2026-06-02",
            notes="list_buckets; per-request bucket_name; paginated list_objects pages.",
        ),
        ConnectorChangelogEntry(
            version="01.03.00",
            date="2026-06-02",
            notes="create_bucket action for new public/private bucket intent.",
        ),
        ConnectorChangelogEntry(
            version="01.04.00",
            date="2026-06-02",
            notes="presign_put and create_bucket accept browser_origin to auto-configure bucket CORS for dashboard uploads.",
        ),
        ConnectorChangelogEntry(
            version="01.06.00",
            date="2026-06-13",
            notes="bulk_export_bucket runs in chained batches for large buckets (manifest + ZIP).",
        ),
    ),
)


# Extend transfer operations and attach proven capability metadata to existing R2 actions.
_object_actions = {action.key: action for action in object_actions("cloudflare_r2")}
CONNECTOR = replace(CONNECTOR, actions=tuple(
    replace(action, implements=_object_actions[action.key].implements,
            required_capabilities=("integrations.execute",))
    if action.key in _object_actions else action for action in CONNECTOR.actions
) + tuple(_object_actions[key] for key in ("put_object", "get_object")))
