"""
Salesforce metadata destructive manifest handling.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional
import json

from g_gremlin.errors import missing_pyyaml_error


@dataclass
class SfdcDestructiveManifest:
    remove_fields: List[Dict[str, str]] = field(default_factory=list)
    remove_validation_rules: List[Dict[str, str]] = field(default_factory=list)
    remove_permission_sets: List[Dict[str, str]] = field(default_factory=list)
    remove_record_types: List[Dict[str, str]] = field(default_factory=list)

    def has_fields(self) -> bool:
        return len(self.remove_fields) > 0

    def has_rules(self) -> bool:
        return len(self.remove_validation_rules) > 0

    def has_permsets(self) -> bool:
        return len(self.remove_permission_sets) > 0

    def has_record_types(self) -> bool:
        return len(self.remove_record_types) > 0


def load_destructive_manifest(pack_dir: Path) -> Optional[SfdcDestructiveManifest]:
    path = pack_dir / "destructive.yaml"
    if not path.exists():
        return None
    raw_text = path.read_text(encoding="utf-8")
    if path.suffix.lower() in {".yaml", ".yml"}:
        try:
            import yaml  # type: ignore
        except Exception as exc:
            raise missing_pyyaml_error() from exc
        payload = yaml.safe_load(raw_text) or {}
    else:
        payload = json.loads(raw_text)

    return SfdcDestructiveManifest(
        remove_fields=list(payload.get("remove_fields") or []),
        remove_validation_rules=list(payload.get("remove_validation_rules") or []),
        remove_permission_sets=list(payload.get("remove_permission_sets") or []),
        remove_record_types=list(payload.get("remove_record_types") or []),
    )


def validate_destructive_coverage(
    manifest: Optional[SfdcDestructiveManifest],
    pack_options: Dict[str, Any],
) -> List[str]:
    errors: List[str] = []
    allow_fields = bool(pack_options.get("allow_delete_fields"))
    allow_rules = bool(pack_options.get("allow_delete_rules"))
    allow_permsets = bool(pack_options.get("allow_delete_permsets"))
    allow_record_types = bool(pack_options.get("allow_delete_record_types"))

    has_manifest = manifest is not None
    has_fields = manifest.has_fields() if manifest else False
    has_rules = manifest.has_rules() if manifest else False
    has_permsets = manifest.has_permsets() if manifest else False
    has_record_types = manifest.has_record_types() if manifest else False

    if allow_fields and not has_fields:
        errors.append("allow_delete_fields enabled but destructive.yaml has no remove_fields")
    if has_fields and not allow_fields:
        errors.append("destructive.yaml remove_fields present but options.allow_delete_fields is false")

    if allow_rules and not has_rules:
        errors.append("allow_delete_rules enabled but destructive.yaml has no remove_validation_rules")
    if has_rules and not allow_rules:
        errors.append("destructive.yaml remove_validation_rules present but options.allow_delete_rules is false")

    if allow_permsets and not has_permsets:
        errors.append("allow_delete_permsets enabled but destructive.yaml has no remove_permission_sets")
    if has_permsets and not allow_permsets:
        errors.append("destructive.yaml remove_permission_sets present but options.allow_delete_permsets is false")

    if allow_record_types and not has_record_types:
        errors.append("allow_delete_record_types enabled but destructive.yaml has no remove_record_types")
    if has_record_types and not allow_record_types:
        errors.append("destructive.yaml remove_record_types present but options.allow_delete_record_types is false")

    if not has_manifest and (allow_fields or allow_rules or allow_permsets or allow_record_types):
        errors.append("destructive.yaml missing but allow_delete_* options enabled")

    return errors
