#!/usr/bin/env python3

# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# /// script
# requires-python = ">=3.11"
# dependencies = [
#    "click",
# ]
# ///

import re
from pathlib import Path

import click

HEADER = "".join(open(__file__).readlines()[2:15])
FABRIC_VERSIONS_TEMPLATE = """
# Fabric release: {fabric_release}

terraform {{
  required_version = ">= {engine_version}"
  required_providers {{
    google = {{
      source  = "hashicorp/google"
      version = ">= {provider_min_version}, < {provider_max_version}" # tftest
    }}
    google-beta = {{
      source  = "hashicorp/google-beta"
      version = ">= {provider_min_version}, < {provider_max_version}" # tftest
    }}
  }}
  provider_meta "google" {{
    module_name = "google-pso-tool/cloud-foundation-fabric/{path}:{fabric_release}-{engine}"
  }}
  provider_meta "google-beta" {{
    module_name = "google-pso-tool/cloud-foundation-fabric/{path}:{fabric_release}-{engine}"
  }}
}}
"""

FAST_VERSIONS_TEMPLATE = "\n# FAST release: {fast_release}\n"


def extract_variables(template, interpolated_string):
  # Find all variable names in the escaped template
  variable_names = re.findall(r'\{(.*?)\}', template)

  # Create a regular expression pattern to match the interpolated string within the template
  pattern = re.sub(r'\{(.*?)\}', r'(.*?)', template)
  pattern = pattern.replace("{{", "{").replace("}}", "}")
  pattern = r'.*?' + pattern + r'.*?'

  # Extract the values using the pattern
  match = re.search(pattern, interpolated_string)
  if match:
    return dict(zip(variable_names, match.groups()))


def process_file(template, file_path, context):
  with file_path.open("w", encoding="utf-8") as f:
    f.write(HEADER)
    f.write(template.format(**context))


@click.command()
@click.option("--fabric-release", help="Override Fabric release version")
@click.option("--provider-min-version",
              help="Override GCP provider min version")
@click.option("--provider-max-version",
              help="Override GCP provider max version")
@click.option("--tf-version", help="Override Terraform version")
@click.option("--tofu-version", help="Override OpenTofu version")
@click.option("--write-defaults/--no-write-defaults", default=False,
              help="Also rewrite default-versions.t*f*")
@click.option("-q", "--quiet", is_flag=True)
def main(write_defaults, quiet, **kwargs):
  root_path = Path(__file__).parents[1]
  overrides = {k: v for k, v in kwargs.items() if v is not None}
  # process versions.tf and versions.tofu
  for engine in ["tf", "tofu"]:
    defaults_fname = root_path / f"default-versions.{engine}"
    defaults = extract_variables(FABRIC_VERSIONS_TEMPLATE,
                                 defaults_fname.read_text())
    context = defaults | overrides
    if kwargs[f'{engine}_version'] is not None:
      context['engine_version'] = kwargs[f'{engine}_version']

    for file_path in root_path.rglob(f"versions.{engine}"):
      if not quiet:
        click.echo(f"Processing {file_path}")
      process_file(FABRIC_VERSIONS_TEMPLATE, file_path, context | {
          "path": file_path.parent.relative_to(root_path),
      })

    if write_defaults:
      if not quiet:
        click.echo(f"Processing {defaults_fname}")
      process_file(FABRIC_VERSIONS_TEMPLATE, defaults_fname, context)

  # process fast_version.txt.
  fast_context = {"fast_release": context["fabric_release"]}
  for file_path in root_path.rglob(f"fast_version.txt"):
    if not quiet:
      click.echo(f"Processing {file_path}")
    process_file(FAST_VERSIONS_TEMPLATE, file_path, fast_context)


if __name__ == "__main__":
  main()
