"""Nova tagging standard custom Checkov rule (D-054, D-109 hard mode).

Checks that all taggable AWS resources have the required Nova tags:
  nova:owner, nova:contract, nova:environment, nova:cost-center

In **hard mode** (P3, REQ-162): the rule hard-fails when a taggable resource
is missing any required `nova:*` tag, OR when a resource carries only the
legacy `acdl:*` tag keys (and no `nova:*` keys). P2 shipped warn mode
(`_WARN_MODE = True`) so the regression gate stayed green during the
parallel-tag transition window; P3 flips to hard-fail (`_WARN_MODE = False`)
once `nova:*` tags are emitted in terraform and the ABAC policy is swapped
to match `nova:*`. P5 keeps hard mode and additionally hard-fails on any
`acdl:*` tag key present at all (no legacy tolerated post-cutoff).

Closes the D-043 deferral (the SKIPPED NOVA_TAG_NAMING placeholder
becomes a real check). Renamed from acdl_tagging.py in P2 (REQ-158);
the Checkov rule ID ACDL_TAG_NAMING → NOVA_TAG_NAMING.
"""

from __future__ import annotations

import sys

from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories

REQUIRED_TAGS = ("nova:owner", "nova:contract", "nova:environment", "nova:cost-center")

# Legacy acdl:* tag keys — the parallel-tag period (P3) emits both nova:*
# and acdl:*; P2 warn mode treats acdl:*-only tags as a warning, not a
# failure. The acdl:* VALUES in tagging-standard.json are left for P3.
LEGACY_TAGS = ("acdl:owner", "acdl:contract", "acdl:environment", "acdl:cost-center")

# Resources that support tags (exclude resources that have no tags attribute)
NON_TAGGABLE_TYPES = (
    "aws_cloudfront_origin_access_control",
    "aws_lambda_function_url",
    "aws_route_table_association",
    "aws_internet_gateway",
)

# P5 hard mode (D-109, REQ-164): `_WARN_MODE = False` (set in P3) AND
# any `acdl:*` tag key present at all is a hard FAIL (P5 tightens from
# P3's "acdl:*-only fails" to "any acdl:* key fails"). The legacy tag
# keys are fully removed from terraform (P3); any remaining `acdl:*` key
# is a rebrand regression.
_WARN_MODE = False


class NovaTaggingStandard(BaseResourceCheck):
    def __init__(self):
        name = "Ensure all taggable AWS resources have required Nova tags"
        check_id = "NOVA_TAG_NAMING"
        supported_resources = ["*"]  # all resources
        categories = [CheckCategories.GENERAL_SECURITY]
        super().__init__(name=name, check_id=check_id, categories=categories, supported_resources=supported_resources)

    def scan_resource_conf(self, conf, entity_type):
        # Skip non-taggable resources
        if entity_type in NON_TAGGABLE_TYPES:
            return CheckResult.PASSED
        # Check for a tags block
        tags = conf.get("tags")
        if not tags:
            return CheckResult.FAILED
        tag_keys = set()
        if isinstance(tags, list) and tags:
            tag_block = tags[0]
            if isinstance(tag_block, dict):
                tag_keys = set(tag_block.keys())
        elif isinstance(tags, dict):
            tag_keys = set(tags.keys())
        # P5 (REQ-164): any legacy acdl:* tag key present = hard FAIL.
        legacy_present = tag_keys & set(LEGACY_TAGS)
        if legacy_present:
            return CheckResult.FAILED
        missing = [t for t in REQUIRED_TAGS if t not in tag_keys]
        if not missing:
            return CheckResult.PASSED
        return CheckResult.FAILED

check = NovaTaggingStandard()