# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import json

import click

from idf_ci.cli._options import (
    option_branch,
    option_commit_sha,
    option_modified_files,
    option_paths,
)
from idf_ci.idf_gitlab import ArtifactManager
from idf_ci.idf_gitlab import build_child_pipeline as build_child_pipeline_cmd
from idf_ci.idf_gitlab import pipeline_variables as pipeline_variables_cmd
from idf_ci.idf_gitlab import test_child_pipeline as test_child_pipeline_cmd
from idf_ci.settings import CiSettings

_SETTINGS = CiSettings()


@click.group()
def gitlab():
    """Group of gitlab related commands"""
    pass


@gitlab.command()
def pipeline_variables():
    """Output dynamic pipeline variables.

    Analyzes the current GitLab pipeline environment and determines what variables to
    set for controlling pipeline behavior. Outputs variables in the format KEY="VALUE"
    for each determined variable, which can be used with GitLab's `export` feature.

    As for the generated variables, please refer to the following link:

    \b
    https://docs.espressif.com/projects/idf-ci/en/latest/references/api/idf_ci.idf_gitlab.html#idf_ci.idf_gitlab.pipeline_variables
    """
    for k, v in pipeline_variables_cmd().items():
        click.echo(f'{k}={v}')


@gitlab.command()
@option_paths
@option_modified_files
@click.option(
    '--compare-manifest-sha-filepath',
    default='.manifest_sha',
    help='Path to the recorded manifest sha file generated by `idf-build-apps dump-manifest-sha`',
)
@click.argument('yaml_output', required=False)
def build_child_pipeline(paths, modified_files, compare_manifest_sha_filepath, yaml_output):
    """Generate build child pipeline yaml file."""
    build_child_pipeline_cmd(
        paths=paths,
        modified_files=modified_files,
        compare_manifest_sha_filepath=compare_manifest_sha_filepath,
        yaml_output=yaml_output,
    )


@gitlab.command()
@click.argument('yaml_output', required=False)
def test_child_pipeline(yaml_output):
    """Generate test child pipeline yaml file."""
    test_child_pipeline_cmd(yaml_output)


@gitlab.command()
@click.option(
    '--type',
    'artifact_type',
    type=click.Choice(_SETTINGS.gitlab.artifacts.available_s3_types),
    help='Type of artifacts to download. If not specified, downloads all types.',
)
@option_commit_sha
@option_branch
@click.option(
    '--presigned-json',
    type=click.Path(dir_okay=False, file_okay=True, exists=True),
    help='Path to the presigned.json file.',
)
@click.argument('folder', required=False)
def download_artifacts(artifact_type, commit_sha, branch, folder, presigned_json):
    """Download artifacts from a GitLab pipeline.

    This command downloads artifacts from either GitLab's built-in storage or S3
    storage, depending on the configuration. The artifacts are downloaded to the
    specified folder (or current directory if not specified).
    """
    manager = ArtifactManager()
    manager.download_artifacts(
        commit_sha=commit_sha,
        branch=branch,
        artifact_type=artifact_type,
        folder=folder,
        presigned_json=presigned_json,
    )


@gitlab.command()
@click.option(
    '--type',
    'artifact_type',
    type=click.Choice(_SETTINGS.gitlab.artifacts.available_s3_types),
    help='Type of artifacts to upload',
)
@option_commit_sha
@option_branch
@click.argument('folder', required=False)
def upload_artifacts(artifact_type, commit_sha, branch, folder):
    """Upload artifacts to S3 storage.

    This command uploads artifacts to S3 storage only. GitLab's built-in storage is not
    supported. The commit SHA is required to identify where to store the artifacts.
    """
    manager = ArtifactManager()
    manager.upload_artifacts(
        commit_sha=commit_sha,
        branch=branch,
        artifact_type=artifact_type,
        folder=folder,
    )


@gitlab.command()
@option_commit_sha
@option_branch
@click.option(
    '--type',
    'artifact_type',
    type=click.Choice(_SETTINGS.gitlab.artifacts.available_s3_types),
    help='Type of artifacts to generate presigned URLs for',
)
@click.option(
    '--expire-in-days',
    type=int,
    default=4,
    help='Expiration time in days for the presigned URLs (default: 4 days)',
)
@click.option(
    '-o',
    '--output',
    type=click.Path(dir_okay=False, file_okay=True),
    help='Path to save the generated presigned URLs. If not specified, will print to stdout.',
)
@click.argument('folder', required=False)
def generate_presigned_json(commit_sha, branch, artifact_type, expire_in_days, output, folder):
    """Generate presigned URLs for artifacts in S3 storage.

    This command generates presigned URLs for artifacts that would be uploaded to S3
    storage. The URLs can be used to download the artifacts directly from S3.
    """
    manager = ArtifactManager()
    presigned_urls = manager.generate_presigned_json(
        commit_sha=commit_sha,
        branch=branch,
        artifact_type=artifact_type,
        folder=folder,
        expire_in_days=expire_in_days,
    )

    if output:
        with open(output, 'w') as f:
            json.dump(presigned_urls, f)
    else:
        click.echo(json.dumps(presigned_urls))


@gitlab.command()
@click.argument('filename', required=True)
def download_known_failure_cases_file(filename):
    """Download known failure cases file from S3 storage."""
    s3_client = ArtifactManager().s3_client

    if s3_client:
        s3_client.fget_object(
            _SETTINGS.gitlab.known_failure_cases_bucket_name,
            filename,
            filename,
        )
    else:
        raise ValueError('Configure S3 storage to download artifacts')
