# Copyright (c) 2020 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
#

import csv
import os

import yaml
from faker import Faker
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text


def get_account_id():
    faker = Faker()
    return faker.random_int(10000000000, 99999999999)


def get_business_unit():
    faker = Faker()
    return faker.bs().split()[0]


def get_owner():
    faker = Faker()
    return faker.name()


def get_cost_center():
    faker = Faker()
    return faker.bban()[:5]


def get_csv_input_template(data):
    return {
        "source-dimension": data.replace("group-rule", "condition-value"),
        "dimension-1": data,
        "dimension-2": data,
        "dimension-3": data,
    }


def get_csv_input_example(business_unit, owner, cost_center):
    return {"Account": get_account_id(), "BusinessUnit": business_unit, "Owner": owner, "CostCenter": cost_center}


def get_costformation_template():
    return {"Dimensions": {}}


def get_dimension_template(name, source_dimension_name, normalize=True):
    dimension_template = {
        "Name": str(name),
        "Source": str(source_dimension_name),
        "Transforms": [{"Type": "Normalize"}],
        "Rules": [],
    }

    if not normalize:
        del dimension_template["Transforms"]

    return dimension_template


def get_group_rule_template(name, condition=False):
    return {"Type": "Group", "Name": str(name), "Conditions": [{f"{'Contains' if condition else 'Equals'}": []}]}


def get_mapping_template():
    template_rows = []

    for i in range(10):
        template_rows.append(get_csv_input_template(f"group-rule-{i + 1}"))

    template_column_names = list(template_rows[0].keys())

    return template_rows, template_column_names


def get_mapping_example():
    example_rows = []

    cost_center = get_cost_center()
    business_unit = get_business_unit()
    owner = get_owner()

    for i in range(10):
        if i % 4 == 0:
            cost_center = get_cost_center()
        if i % 2 == 0:
            business_unit = get_business_unit()
            owner = get_owner()

        example_rows.append(get_csv_input_example(business_unit, owner, cost_center))

    example_column_names = list(example_rows[0].keys())

    return example_rows, example_column_names


def normalize_name(name):
    for c in ".,/#!$%^&*;:=_~()'":
        name = str(name).replace(c, "-")

    return name.lower()


def display_conversion_summary(costformation, mapping_name, output_file, rows_processed):
    """Display a visual summary of the conversion results."""
    console = Console()

    # Calculate statistics
    dimensions_count = len(costformation.get("Dimensions", {}))
    total_rules = 0
    total_members = 0
    dimension_stats = []

    for dim_name, dimension in costformation.get("Dimensions", {}).items():
        rules = dimension.get("Rules", [])
        rules_count = len(rules)
        members_count = sum(
            len(rule.get("Conditions", [{}])[0].get("Equals", [])) + len(rule.get("Conditions", [{}])[0].get("Contains", [])) for rule in rules
        )
        total_rules += rules_count
        total_members += members_count
        dimension_stats.append((dim_name, rules_count, members_count))

    # Create title
    title = Text("🎯 CloudZero Cost Formation Mapping Conversion Complete", style="bold cyan")

    # Create summary panel content
    summary_content = f"""[bold green]✓[/bold green] Successfully processed [bold]{rows_processed}[/bold] rows from CSV
[bold green]✓[/bold green] Created [bold]{dimensions_count}[/bold] dimension{"s" if dimensions_count != 1 else ""}
[bold green]✓[/bold green] Generated [bold]{total_rules}[/bold] grouping rules
[bold green]✓[/bold green] Mapped [bold]{total_members}[/bold] total members

[bold]Input:[/bold]  {mapping_name}
[bold]Output:[/bold] {output_file}"""

    # Display main summary
    console.print("\n")
    console.print(Panel(summary_content, title=title, border_style="cyan"))

    # Create dimensions breakdown table
    if dimension_stats:
        table = Table(title="📊 Dimensions Breakdown", show_header=True, header_style="bold magenta")
        table.add_column("Dimension Name", style="cyan", no_wrap=True)
        table.add_column("Group Rules", justify="right", style="green")
        table.add_column("Total Members", justify="right", style="yellow")

        for dim_name, rules_count, members_count in dimension_stats:
            table.add_row(dim_name, str(rules_count), str(members_count))

        console.print("\n")
        console.print(table)

    # Add helpful information
    info_panel = Panel(
        """[bold]What was created:[/bold]
• A CloudZero Cost Formation YAML file that maps source account IDs to business dimensions
• Each dimension contains grouping rules that categorize your cloud resources
• These mappings help organize cloud costs by business units, teams, or custom categories

[bold]Next steps:[/bold]
1. Review the generated YAML file for accuracy
2. Upload to CloudZero using the Cost Formation UI or API
3. View your newly organized cost data in CloudZero dashboards""",
        title="💡 About Your Cost Formation Rules",
        border_style="blue",
    )

    console.print("\n")
    console.print(info_panel)
    console.print("\n")


def add_member(group_rule, member_name, group_rule_condition):
    group_rule["Conditions"][0][f"{'Contains' if group_rule_condition else 'Equals'}"].append(str(member_name))


def get_dimension_names(row):
    source_dimension_name = str(list(row.keys())[0])
    dimension_names = [str(name) for name in row if name][1:]

    return dimension_names, source_dimension_name


def generate_template():
    template_rows, template_column_names = get_mapping_template()

    try:
        mapping_template_file_name = "mapping_template.csv"

        with open(mapping_template_file_name, mode="w") as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=template_column_names)
            writer.writeheader()

            for row in template_rows:
                writer.writerow(row)

        print(f'Mapping template saved to "./{mapping_template_file_name}"!')

    except Exception as err:
        print(f"Something went wrong: {err}")
        exit(-1)


def generate_example():
    example_rows, example_column_names = get_mapping_example()

    try:
        mapping_example_file_name = "mapping_example.csv"

        with open(mapping_example_file_name, mode="w") as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=example_column_names)
            writer.writeheader()

            for row in example_rows:
                writer.writerow(row)

            print(f'Mapping example saved to "./{mapping_example_file_name}"!')

    except Exception as err:
        print(f"Something went wrong: {err}")
        exit(-1)


def convert_mapping(arguments):
    mapping_name = arguments.get("--file")
    group_rule_condition = arguments.get("--condition-contains")
    dimension_normalize = arguments.get("--normalize")

    if arguments.get("-o") or arguments.get("--output"):
        mapping_rules_name = arguments.get("-o") or arguments.get("--output")
    elif mapping_name and isinstance(mapping_name, str):
        # Extract just the filename without path and extension
        base_name = os.path.basename(mapping_name)
        name_without_ext = os.path.splitext(base_name)[0]
        # Use the directory of the input file for output
        output_dir = os.path.dirname(mapping_name)
        mapping_rules_name = os.path.join(output_dir, name_without_ext)
    else:
        print("Error: --file parameter is required")
        exit(-1)

    try:
        with open(mapping_name, encoding="utf-8-sig") as csv_file:
            mapping_table = csv.DictReader(csv_file)
            group_rules_memo = {}
            group_rule_names_memo = {}
            source_dimension_name = ""
            rows_processed = 0

            costformation = get_costformation_template()

            for row in mapping_table:
                rows_processed += 1
                if not source_dimension_name:
                    dimension_names, source_dimension_name = get_dimension_names(row)

                    if len(dimension_names) < 1 or not source_dimension_name:
                        print("1 source dimension and at least 1 dimension required")
                        print('Run "czops cf mapping_template" for details')
                        exit(-1)

                for dimension_name in dimension_names:
                    if dimension_name not in group_rules_memo:
                        group_rules_memo[dimension_name] = {}

                    if row[dimension_name]:
                        normalized_group_rule_name = normalize_name(row[dimension_name])
                        if normalized_group_rule_name in group_rule_names_memo:
                            group_rule_name = group_rule_names_memo[normalized_group_rule_name]

                        else:
                            group_rule_name = row[dimension_name]
                            group_rule_names_memo[normalized_group_rule_name] = row[dimension_name]

                        if group_rule_name not in group_rules_memo[dimension_name]:
                            group_rules_memo[dimension_name][group_rule_name] = get_group_rule_template(
                                group_rule_name, condition=group_rule_condition
                            )

                        group_rule = group_rules_memo[dimension_name][group_rule_name]

                        member_name = normalize_name(row[source_dimension_name]) if dimension_normalize else row[source_dimension_name]

                        if member_name and member_name not in group_rule["Conditions"][0][f"{'Contains' if group_rule_condition else 'Equals'}"]:
                            add_member(group_rule, member_name, group_rule_condition)

                        if dimension_name not in costformation["Dimensions"]:
                            costformation["Dimensions"][dimension_name] = get_dimension_template(
                                dimension_name, source_dimension_name, normalize=dimension_normalize
                            )

                        dimension = costformation["Dimensions"][dimension_name]

                        if group_rule not in dimension["Rules"]:
                            dimension["Rules"].append(group_rule)

    except Exception as err:
        print(f"Something went wrong: {err}")
        exit(-1)

    output_file = f"{mapping_rules_name}_rules.cz.yaml"

    try:
        with open(output_file, "w") as outfile:
            yaml.dump(costformation, outfile, default_flow_style=False, sort_keys=False)

    except Exception as err:
        print(f"Something went wrong: {err}")
        exit(-1)

    # Display the visual summary
    display_conversion_summary(costformation, mapping_name, output_file, rows_processed)
