"""Field planning for record.create / record.edit.

This is product mechanics (which keys are visible, hidden, or system-owned),
not a form library. Hosts still render with form.standard and the framework's
native inputs. Persistence stays on adapter.records.
"""

from __future__ import annotations

import re
from typing import Any

FILE_ID_RE = re.compile(r"^file_[0-9a-f]{32}$")

SYSTEM_FIELD_KEYS = frozenset(
    {
        "id",
        "owner_user_id",
        "created_by",
        "updated_by",
        "project_id",
        "workspace_id",
        "created_at",
        "updated_at",
    }
)

TEXTAREA_MAX_BYTES_THRESHOLD = 1024

FORBIDDEN_RAW_HTML_MARKERS = (
    "v-html",
    "dangerouslySetInnerHTML",
    "innerHTML",
    "markdown",
)


def utf8_byte_length(value: str | None) -> int:
    return len((value or "").encode("utf-8"))


def html_escape(value: Any) -> str:
    text = "" if value is None else str(value)
    return (
        text.replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
        .replace("'", "&#39;")
    )


def _as_options(field: dict[str, Any]) -> list[str]:
    raw = field.get("options") or []
    return [str(item) for item in raw]


def plan_record_form_fields(
    schema: dict[str, Any] | None,
    visible_fields: list[str] | None = None,
) -> dict[str, list[dict[str, Any]]]:
    """Derive visible + hidden/fixed fields from an entity schema.

    A required select with exactly one option is hidden and submitted as
    that fixed value. The rule is generic.
    """
    visible: list[dict[str, Any]] = []
    hidden: list[dict[str, Any]] = []
    for field in (schema or {}).get("fields") or []:
        if not isinstance(field, dict):
            continue
        key = str(field.get("key") or "")
        if not key or key in SYSTEM_FIELD_KEYS:
            continue
        if visible_fields is not None and key not in visible_fields:
            continue
        options = _as_options(field)
        field_type = str(field.get("type") or "text")
        required = bool(field.get("required"))
        if field_type == "select" and len(options) == 1:
            hidden.append(
                {
                    "key": key,
                    "type": "hidden",
                    "label": field.get("name") or key,
                    "required": required,
                    "fixed_value": options[0],
                    "value": options[0],
                }
            )
            continue
        max_bytes = field.get("max_bytes")
        if field_type == "select":
            input_type = "select"
        elif field_type == "textarea":
            input_type = "textarea"
        elif field_type == "text" and int(max_bytes or 0) > TEXTAREA_MAX_BYTES_THRESHOLD:
            input_type = "textarea"
        elif field_type == "file":
            input_type = "file"
        elif field_type in {"text", "email", "number", "phone"}:
            input_type = field_type
        else:
            input_type = "text"
        planned = {
            "key": key,
            "label": field.get("name") or key,
            "type": input_type,
            "required": required,
        }
        if input_type == "select":
            planned["options"] = options
        if max_bytes is not None:
            planned["max_bytes"] = int(max_bytes)
        visible.append(planned)
    return {"visible": visible, "hidden": hidden}


def merge_submit_values(
    schema: dict[str, Any] | None,
    user_values: dict[str, Any] | None,
    visible_fields: list[str] | None = None,
) -> dict[str, Any]:
    """Build the record payload. System keys are never user-editable."""
    plan = plan_record_form_fields(schema, visible_fields)
    incoming = dict(user_values or {})
    for key in SYSTEM_FIELD_KEYS:
        incoming.pop(key, None)
    out: dict[str, Any] = {}
    for field in plan["hidden"]:
        out[field["key"]] = field["fixed_value"]
    for field in plan["visible"]:
        if field["key"] not in incoming:
            continue
        value = incoming[field["key"]]
        if field["type"] == "file":
            out[field["key"]] = canonical_file_id(value)
        else:
            out[field["key"]] = value
    return out


def canonical_file_id(value: Any) -> str:
    """Persist only a P2HS file_id. Provider locators are never record identity."""
    if isinstance(value, dict):
        value = value.get("file_id")
    if not isinstance(value, str):
        return ""
    trimmed = value.strip()
    return trimmed if FILE_ID_RE.fullmatch(trimmed) else ""


def initial_form_values(
    schema: dict[str, Any] | None,
    record: dict[str, Any] | None = None,
    visible_fields: list[str] | None = None,
) -> dict[str, Any]:
    plan = plan_record_form_fields(schema, visible_fields)
    data = (record or {}).get("data") if isinstance((record or {}).get("data"), dict) else record or {}
    values: dict[str, Any] = {}
    for field in plan["hidden"]:
        values[field["key"]] = field["fixed_value"]
    for field in plan["visible"]:
        values[field["key"]] = data.get(field["key"], "")
    return values


def form_standard_can_serve_authenticated_crud() -> dict[str, Any]:
    """Inspection result for 11D5E: reuse form.standard as presentation only."""
    return {
        "reuse": True,
        "owns_submit_transport": False,
        "public_submission_parent": "public form submit adapter",
        "authenticated_parent": "createRecord / patchRecord",
        "missing_before_11d5e": ("select", "hidden_fixed_single_option", "initial_values"),
        "fork_product_form": False,
    }
