"""
This module provides functions to trigger a build in TeamCity,
fetch build logs, check build status, and stream build logs while
monitoring the status of the build.
"""

import os
import time
import sys
import requests
from actions_logging.app_logging import logger
from constants import TEAMCITY_URL

TEAMCITY_SERVER = os.getenv('TEAMCITY_SERVER', 'https://ci.safersoftware.net')
BUILD_CONFIGURATION_ID = os.getenv('BUILD_CONFIGURATION_ID', 'Qa_Resilience_ResilienceMac')
API_KEY = os.getenv('TEAMCITY_API_KEY')  # API key is mandatory, no default
POLL_INTERVAL = int(os.getenv('POLL_INTERVAL', '10'))  # Polling interval in seconds

headers = {
    'Accept': 'application/json',
    'Authorization': f'Bearer {API_KEY}'
}

def get_custom_parameters(prefix='TC_PARAM_'):
    """Get custom parameters from environment variables."""
    params = {}
    for key, value in os.environ.items():
        if key.startswith(prefix):
            param_name = key[len(prefix):]
            # Replace double underscores with dots
            param_name = param_name.replace('__', '.')
            # Split the value by delimiter for list parameters
            params[param_name] = value
    return params

def trigger_teamcity_build(custom_parameters):
    """Triggers a build in TeamCity with custom parameters and returns the build ID."""
    url = f"{TEAMCITY_SERVER}/app/rest/buildQueue"
    data = {
        "buildType": {"id": BUILD_CONFIGURATION_ID},
        "properties": {"property": [{"name": k, "value": v }
                                   for k, v in custom_parameters.items()]}
    }

    response = requests.post(url, headers=headers, json=data)

    if response.status_code == 200:
        try:
            build_id = response.json().get('id')
            # If running in GitHub Actions, write the build_id to the GITHUB_OUTPUT file.
            github_output = os.getenv("GITHUB_OUTPUT")
            if github_output and build_id:
                with open(github_output, "a") as f:
                    f.write(f"build_id={build_id}\n")
            return build_id
        except (KeyError, ValueError):
            logger.info("Error processing JSON response. Here's the response:", response.text)
            return None
    else:
        logger.info(f"Failed to trigger build. Status code: {response.status_code}, "
              f"Response content: {response.text}")
        response.raise_for_status()
        return None


def fetch_build_logs(build_id):
    """Fetches the build logs for a given build ID."""
    url = f"{TEAMCITY_SERVER}/downloadBuildLog.html?buildId={build_id}"
    response = requests.get(url, headers=headers)
    return response.text

def check_build_status(build_id):
    """Checks the status of a build in TeamCity and returns its state and status."""
    url = f"{TEAMCITY_SERVER}/app/rest/builds/id:{build_id}"
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        build_info = response.json()
        return build_info.get('state'), build_info.get('status')
    logger.info(f"Failed to check build status. Status code: {response.status_code}, "
          f"Response content: {response.text}")
    response.raise_for_status()
    return None, None

def has_build_started(build_id):
    """Check if the build with the given ID has started in TeamCity."""
    url = f"{TEAMCITY_SERVER}/app/rest/builds/id:{build_id}"
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        build_info = response.json()
        return build_info.get('state') == 'running'
    else:
        logger.info(f"Failed to check if build started. Status code: {response.status_code}, "
              f"Response content: {response.text}")
        return False

def stream_build_logs_and_check_status(build_id):
    """Streams build logs and checks the build status periodically."""
    printed_lines = set()

    # Wait until the build starts
    while not has_build_started(build_id):
        logger.info(f"Waiting for build {build_id} to start...")
        time.sleep(POLL_INTERVAL)

    while True:
        logs = fetch_build_logs(build_id)
        lines = logs.split('\n')

        for line in lines:
            if line not in printed_lines and 'running for' not in line and 'Current time' not in line:
                logger.info(line)
                printed_lines.add(line)

        build_url = f"{TEAMCITY_URL}/buildConfiguration/{BUILD_CONFIGURATION_ID}/{build_id}"
        logger.info_green(f"Build URL: {build_url}")

        build_state, build_status = check_build_status(build_id)
        if build_status is None:
            logger.warning(f"Could not fetch build status for build ID: {build_id}")
            return False

        if build_state and build_state.lower() != "running":
            return build_status.lower() == 'success'

        time.sleep(POLL_INTERVAL)

def main():
    """Main function that triggers and monitors a TeamCity build."""
    if not API_KEY:
        raise ValueError("TEAMCITY_API_KEY environment variabls are required")
    if not BUILD_CONFIGURATION_ID:
        raise ValueError("BUILD_CONFIGURATION_ID environment variabls are required")

    custom_parameters = get_custom_parameters()

    build_id = trigger_teamcity_build(custom_parameters)

    if build_id is not None:
        build_url = f"{TEAMCITY_URL}/buildConfiguration/{BUILD_CONFIGURATION_ID}/{build_id}"
        logger.info_green(f"Build URL: {build_url}")
        success = stream_build_logs_and_check_status(build_id)
        logger.info("Build completed successfully." if success else "Build failed.")
        sys.exit(0 if success else 1)
    logger.error("Failed to trigger TeamCity build.")
    sys.exit(1)

if __name__ == "__main__":
    main()
