"""Form file references. Verification only — no binary transfer or storage.file.*.

7C stays pure (FormFileRef shape). Existence and project ownership are checked
here, before 7D issues a submission_id. Upload bytes belong to platform Cloud
files (`file_` + 32 hex), not Forms and not customer `storage.file.*`.
"""
from __future__ import annotations

from collections.abc import Mapping
from typing import Any, Protocol

from pydantic import BaseModel, ConfigDict, StrictStr

from src.domain.forms.canonical import (
    FILE_CARDINALITY,
    FILE_ID_PATTERN,
    FILE_ID_PREFIX,
    FILE_RUNTIME_SUPPORT,
    FormDefinition,
    parse_form_file_ref,
)
from src.domain.forms.runtime import (
    FormSubmissionRuntimeResult,
    accept_form_submission,
)
from src.domain.forms.validation import FormFieldError, validate_form_values

INVALID_FILE = "invalid_file"
CUSTOMER_STORAGE_FILE_IS_NOT_FORM_UPLOAD = True
UPLOAD_EXECUTION_DOMAIN = "P"
RECORD_FILE_SEMANTIC = "file_reference"

FORMS_FILE_UPLOADS: dict[str, Any] = {
    "slice_id": "7f_file_uploads",
    "status": "frozen",
    "file_runtime_support": FILE_RUNTIME_SUPPORT,
    "canonical_value": "FormFileRef",
    "record_value_type": "text",
    "record_semantic_type": RECORD_FILE_SEMANTIC,
    "file_id_prefix": FILE_ID_PREFIX,
    "file_id_pattern": FILE_ID_PATTERN,
    "file_id_source": "platform_cloud_randomId_file",
    "cardinality": FILE_CARDINALITY,
    "bytes_in_form_submission": False,
    "provider_native_ids": False,
    "customer_storage_file_star": False,
    "upload_execution_domain": UPLOAD_EXECUTION_DOMAIN,
    "form_file_capability": False,
    "public_forms_upload_route": True,
    "orphan_policy": "delegated_to_platform_cloud_files_lifecycle",
    "malware_scan": "not_claimed",
    "mime_in_form_ref": False,
    "filename_in_form_ref": False,
    "signed_urls_in_form_ref": False,
    "file_to_submission": "many_to_many_not_inferred_one_to_one",
    "deletion": "submission_retains_file_id",
    "anti_abuse": "deferred_7g",
    "form_submit_capability": False,
    "codegen": False,
    "docs": "docs/audits/FORMS_FILE_UPLOADS_7F.md",
}


def compiled_file_reference_field(field_key: str) -> dict[str, str]:
    """Metadata for compiling a form file field into a Cloud record schema."""
    return {"key": field_key, "type": "text", "semantic_type": RECORD_FILE_SEMANTIC}


class FormFileRecord(BaseModel):
    """Verified platform file. Metadata stays in the Files layer."""

    model_config = ConfigDict(extra="forbid", frozen=True)
    file_id: StrictStr
    project_id: StrictStr


class FormFileDirectory(Protocol):
    """Project-scoped existence lookup. No R2/S3/connector calls in Forms."""

    def get(self, project_id: str, file_id: str) -> FormFileRecord | None: ...


class InMemoryFormFileDirectory:
    """Test/reference directory. Not a production upload surface."""

    def __init__(self) -> None:
        self._files: dict[tuple[str, str], FormFileRecord] = {}

    def put(self, record: FormFileRecord) -> FormFileRecord:
        self._files[(record.project_id, record.file_id)] = record
        return record

    def delete(self, project_id: str, file_id: str) -> None:
        self._files.pop((project_id, file_id), None)

    def get(self, project_id: str, file_id: str) -> FormFileRecord | None:
        return self._files.get((project_id, file_id))


def _file_error(field: str, code: str, message: str) -> FormFieldError:
    return FormFieldError(field=field, code=code, message=message)


def verify_file_fields(
    definition: FormDefinition,
    raw: Mapping[str, Any],
    *,
    project_id: str,
    files: FormFileDirectory,
) -> tuple[dict[str, Any], tuple[FormFieldError, ...]]:
    """Replace valid file fields with FormFileRef; collect ownership failures.

    Shape errors are left for 7C. Existence/project failures are `invalid_file`.
    """
    patched: dict[str, Any] = dict(raw)
    errors: list[FormFieldError] = []
    for field in definition.fields:
        if field.type != "file" or field.key not in raw:
            continue
        value = raw[field.key]
        if value is None or (isinstance(value, str) and value.strip() == ""):
            continue
        parsed = parse_form_file_ref(value)
        if parsed is None:
            continue
        record = files.get(project_id, parsed.file_id)
        if record is None or record.project_id != project_id:
            errors.append(
                _file_error(
                    field.key,
                    INVALID_FILE,
                    "This file is not available for this form.",
                )
            )
            continue
        patched[field.key] = parsed
    return patched, tuple(errors)


def accept_form_submission_with_files(
    definition: FormDefinition,
    raw: Mapping[str, Any],
    *,
    project_id: str,
    files: FormFileDirectory,
    form_key: str | None = None,
    conditions=None,
    submission_id_factory=None,
    clock=None,
) -> FormSubmissionRuntimeResult:
    """Verify file refs, then 7C+7D. Does not accept request bodies or bytes."""
    patched, file_errors = verify_file_fields(
        definition, raw, project_id=project_id, files=files
    )
    if file_errors:
        validation = validate_form_values(definition, patched, form_key=form_key)
        return FormSubmissionRuntimeResult(
            accepted=False,
            submission=None,
            errors=tuple(file_errors) + tuple(validation.errors),
            validation=validation,
        )
    kwargs: dict[str, Any] = {"form_key": form_key, "conditions": conditions}
    if submission_id_factory is not None:
        kwargs["submission_id_factory"] = submission_id_factory
    if clock is not None:
        kwargs["clock"] = clock
    return accept_form_submission(definition, patched, **kwargs)
