"""
Terraform HCL Generator
========================

Generate Terraform configuration from OpenFinOps resources.
"""

# Copyright (c) 2025 OpenFinOps Contributors
# Licensed under the Apache License, Version 2.0

from typing import Dict, Any, List, Optional
from pathlib import Path
import json
import logging

logger = logging.getLogger(__name__)


class TerraformGenerator:
    """
    Generates Terraform HCL configuration from OpenFinOps resources.
    """

    def __init__(self, provider_config: Optional[Dict[str, Any]] = None):
        """
        Initialize Terraform generator.

        Args:
            provider_config: Provider configuration
        """
        self.provider_config = provider_config or {}
        self.resources: List[Dict[str, Any]] = []

    def add_resource(self, resource: Any):
        """
        Add resource to Terraform configuration.

        Args:
            resource: Resource instance with to_terraform() method
        """
        if hasattr(resource, "to_terraform"):
            self.resources.append(resource.to_terraform())
        else:
            logger.warning(f"Resource does not have to_terraform() method: {resource}")

    def generate_provider_block(self) -> str:
        """
        Generate provider configuration block.

        Returns:
            HCL provider block
        """
        hcl = 'provider "finopsmetrics" {\n'

        for key, value in self.provider_config.items():
            if isinstance(value, str):
                hcl += f'  {key} = "{value}"\n'
            elif isinstance(value, bool):
                hcl += f'  {key} = {str(value).lower()}\n'
            elif isinstance(value, (int, float)):
                hcl += f"  {key} = {value}\n"
            else:
                hcl += f"  {key} = {json.dumps(value)}\n"

        hcl += "}\n"
        return hcl

    def generate_resource_block(self, resource: Dict[str, Any]) -> str:
        """
        Generate resource configuration block.

        Args:
            resource: Resource configuration

        Returns:
            HCL resource block
        """
        if "resource" not in resource:
            return ""

        hcl = ""
        for resource_type, resources in resource["resource"].items():
            for resource_name, config in resources.items():
                hcl += f'resource "{resource_type}" "{resource_name}" {{\n'
                hcl += self._generate_config_block(config, indent=2)
                hcl += "}\n\n"

        return hcl

    def _generate_config_block(self, config: Dict[str, Any], indent: int = 0) -> str:
        """
        Generate configuration block with proper indentation.

        Args:
            config: Configuration dictionary
            indent: Indentation level

        Returns:
            HCL configuration block
        """
        hcl = ""
        prefix = " " * indent

        for key, value in config.items():
            if isinstance(value, str):
                hcl += f'{prefix}{key} = "{value}"\n'
            elif isinstance(value, bool):
                hcl += f"{prefix}{key} = {str(value).lower()}\n"
            elif isinstance(value, (int, float)):
                hcl += f"{prefix}{key} = {value}\n"
            elif isinstance(value, list):
                hcl += self._generate_list_block(key, value, indent)
            elif isinstance(value, dict):
                hcl += f"{prefix}{key} {{\n"
                hcl += self._generate_config_block(value, indent + 2)
                hcl += f"{prefix}}}\n"
            else:
                hcl += f"{prefix}{key} = {json.dumps(value)}\n"

        return hcl

    def _generate_list_block(self, key: str, values: List[Any], indent: int) -> str:
        """
        Generate list block.

        Args:
            key: Configuration key
            values: List of values
            indent: Indentation level

        Returns:
            HCL list block
        """
        prefix = " " * indent
        hcl = f"{prefix}{key} = [\n"

        for value in values:
            if isinstance(value, str):
                hcl += f'{prefix}  "{value}",\n'
            elif isinstance(value, dict):
                hcl += f"{prefix}  {{\n"
                hcl += self._generate_config_block(value, indent + 4)
                hcl += f"{prefix}  }},\n"
            else:
                hcl += f"{prefix}  {json.dumps(value)},\n"

        hcl += f"{prefix}]\n"
        return hcl

    def generate(self) -> str:
        """
        Generate complete Terraform configuration.

        Returns:
            Complete HCL configuration
        """
        hcl = "# Generated by OpenFinOps IaC\n\n"

        # Add terraform block
        hcl += "terraform {\n"
        hcl += "  required_providers {\n"
        hcl += "    finopsmetrics = {\n"
        hcl += '      source  = "finopsmetrics/finopsmetrics"\n'
        hcl += '      version = "~> 1.0"\n'
        hcl += "    }\n"
        hcl += "  }\n"
        hcl += "}\n\n"

        # Add provider block
        if self.provider_config:
            hcl += self.generate_provider_block()
            hcl += "\n"

        # Add resource blocks
        for resource in self.resources:
            hcl += self.generate_resource_block(resource)

        return hcl

    def save(self, output_path: str):
        """
        Save Terraform configuration to file.

        Args:
            output_path: Output file path
        """
        hcl = self.generate()
        Path(output_path).write_text(hcl)
        logger.info(f"Saved Terraform configuration to: {output_path}")


def generate_terraform(
    provider_config: Dict[str, Any],
    resources: List[Any],
    output_path: Optional[str] = None,
) -> str:
    """
    Generate Terraform configuration from resources.

    Args:
        provider_config: Provider configuration
        resources: List of resources
        output_path: Optional output file path

    Returns:
        Generated HCL configuration
    """
    generator = TerraformGenerator(provider_config)

    for resource in resources:
        generator.add_resource(resource)

    hcl = generator.generate()

    if output_path:
        generator.save(output_path)

    return hcl


def generate_module(
    module_name: str,
    resources: List[Any],
    variables: Optional[Dict[str, Any]] = None,
    outputs: Optional[Dict[str, Any]] = None,
) -> Dict[str, str]:
    """
    Generate Terraform module.

    Args:
        module_name: Module name
        resources: List of resources
        variables: Module variables
        outputs: Module outputs

    Returns:
        Dictionary of module files (filename -> content)
    """
    files = {}

    # Generate main.tf
    generator = TerraformGenerator()
    for resource in resources:
        generator.add_resource(resource)
    files["main.tf"] = generator.generate()

    # Generate variables.tf
    if variables:
        var_hcl = "# Module variables\n\n"
        for var_name, var_config in variables.items():
            var_hcl += f'variable "{var_name}" {{\n'
            if "description" in var_config:
                var_hcl += f'  description = "{var_config["description"]}"\n'
            if "type" in var_config:
                var_hcl += f'  type        = {var_config["type"]}\n'
            if "default" in var_config:
                default = var_config["default"]
                if isinstance(default, str):
                    var_hcl += f'  default     = "{default}"\n'
                else:
                    var_hcl += f"  default     = {json.dumps(default)}\n"
            var_hcl += "}\n\n"
        files["variables.tf"] = var_hcl

    # Generate outputs.tf
    if outputs:
        out_hcl = "# Module outputs\n\n"
        for out_name, out_config in outputs.items():
            out_hcl += f'output "{out_name}" {{\n'
            if "description" in out_config:
                out_hcl += f'  description = "{out_config["description"]}"\n'
            if "value" in out_config:
                out_hcl += f'  value       = {out_config["value"]}\n'
            out_hcl += "}\n\n"
        files["outputs.tf"] = out_hcl

    return files


def save_module(module_name: str, files: Dict[str, str], base_dir: str = "."):
    """
    Save Terraform module files.

    Args:
        module_name: Module name
        files: Dictionary of files (filename -> content)
        base_dir: Base directory
    """
    module_dir = Path(base_dir) / module_name
    module_dir.mkdir(parents=True, exist_ok=True)

    for filename, content in files.items():
        filepath = module_dir / filename
        filepath.write_text(content)
        logger.info(f"Saved module file: {filepath}")


# Example Terraform configurations
def example_cost_management_config() -> str:
    """
    Generate example cost management configuration.

    Returns:
        Example Terraform HCL
    """
    from .resources import budget, alert, policy
    from .provider import ProviderConfig

    # Provider configuration
    provider_config = ProviderConfig(
        endpoint="https://api.finopsmetrics.io",
        region="us-east-1",
    ).to_terraform()

    # Create resources
    resources = []

    # Budget
    budget_resource = budget(
        name="monthly_infrastructure_budget",
        amount=10000.0,
        period="monthly",
        filters={"team": "infrastructure"},
        alerts=[
            {"threshold": 80, "channels": ["email", "slack"]},
            {"threshold": 100, "channels": ["email", "pagerduty"]},
        ],
    )
    resources.append(budget_resource)

    # Policy
    policy_resource = policy(
        name="tag_enforcement",
        policy_type="tagging",
        rules=[
            {"tag": "owner", "required": True},
            {"tag": "environment", "required": True},
        ],
        severity="error",
    )
    resources.append(policy_resource)

    # Alert
    alert_resource = alert(
        name="high_cost_alert",
        condition={"metric": "daily_cost", "aggregation": "sum"},
        threshold=1000.0,
        comparison="greater_than",
        notification_channels=["email"],
    )
    resources.append(alert_resource)

    # Generate Terraform
    return generate_terraform(provider_config, resources)
