import os
import shutil
from datetime import datetime
from typing import TextIO
import pytz
import requests
from aws.client import create_client_from_session
from aws.constants import PROD_ENVS
from aws.assume_iam import assume_role_get_creds
from actions_logging.app_logging import logger
from aws.acm_apis import list_certificates
from aws.env_info import get_env_region
from github.env import exit_on_error_and_write_summary
from monitoring.constants import PROMETHEUS_URL


def send_metrics_to_prometheus(file_name, prometheus_url):
    """
    Send the metrics_file to prometheus
    :param file_name:
    :param prometheus_url:
    """
    try:
        logger.info(f"Sending metrics from {file_name} file to prometheus: {prometheus_url}")
        with open(file_name, 'rb') as f:
            logger.debug("sending post request with 'rb' file data to prometheus")
            response = requests.post(prometheus_url, data=f)
            logger.debug(f"response status code from prometheus: {response.status_code}")
            response.raise_for_status()
        logger.info_green_bg(f"Sent metrics to prometheus: {response.status_code} - {response.text}")
    except Exception as e:
        raise RuntimeError(f"Error sending metrics to prometheus: {e}")


def process_imported_certificate(cert_arn, cert_data):
    """
    Process an imported certificate, calculate its expiration details, and generate a metrics line.
    :param cert_arn: The ARN of the certificate
    :param cert_data: The details of the certificate
    :return: A formatted metrics line
    """
    try:
        logger.info(f"cert {cert_arn} is imported")
        expire_date = cert_data.get('NotAfter', '')
        remaining_days = (expire_date - datetime.now().replace(tzinfo=pytz.utc)).days
        logger.debug(f"days until expired: {remaining_days}")
        domain_name = cert_data.get('DomainName', 'unknown')
        line = f'imported_certs_acm_days_to_expire{{domain_name="{domain_name}",expire_at="{expire_date}"}} {remaining_days}\n'
        return line
    except Exception as e:
        logger.error(f"Error processing imported certificate {cert_arn}: {e}")
        return ''


def process_cert_if_imported(cert, client, metrics_file: TextIO):
    """
    Process a certificate to check if it is imported and write its remains days to the metrics file.
    :param cert:
    :param client:
    :param metrics_file:
    :return:
    """
    try:
        cert_arn = cert.get('CertificateArn')
        if not cert_arn:
            logger.warning(f"cert does not have an ARN: {cert}")
            return
        cert_details = client.describe_certificate(CertificateArn=cert_arn)
        logger.debug(f"got cert details: {cert_details}")
        cert_data = cert_details.get('Certificate', {})
        cert_type = cert_data.get('Type', '')
        if cert_type == 'IMPORTED':
            metric_line = process_imported_certificate(cert_arn, cert_data)
            logger.info(f"Writing to file: {metric_line}")
            metrics_file.write(metric_line)
    except Exception as e:
        raise RuntimeError(f"Error processing imported certificate {cert}: {e}")


def process_acm_imported_certs_for_env(prod_env, metrics_file: TextIO):
    """
    Process ACM imported certificates for a specific environment.
    :param prod_env: prod env name
    :param metrics_file: file object to write metrics to
    """
    try:
        logger.info(f"Getting ACM imported certs for {prod_env}")
        creds = assume_role_get_creds(prod_env)
        env_region = get_env_region(prod_env)
        client = create_client_from_session('acm', env_region, creds)
        logger.info(f"got client for {prod_env} in region {env_region}")
        cert_list = list_certificates(client, CertificateStatuses=['ISSUED'])
        logger.info(f"got {len(cert_list)} certs for {prod_env}. will check if they are imported")
        for cert in cert_list:
            process_cert_if_imported(cert, client, metrics_file)
    except Exception as e:
        raise RuntimeError(f"Error processing ACM imported certs for {prod_env}: {e}")


def main():
    """
    Main function to get ACM imported certificates and write them to a file. and export the file to prometheus
    """
    file_name = 'metrics-to-export-acm'
    try:
        logger.info_green_bg(f"Getting ACM imported certs for {PROD_ENVS}")
        logger.info(f"removing file {file_name} if exists before the metrics collection")
        shutil.rmtree(file_name, ignore_errors=True)
        prometheus_url = os.getenv('PROMETHEUS_URL', PROMETHEUS_URL)
        with open(file_name, 'w') as metrics_to_export:
            for prod_env in PROD_ENVS:
                process_acm_imported_certs_for_env(prod_env, metrics_to_export)
            logger.info_green_bg("Finished getting ACM imported certs and write it to file")
        send_metrics_to_prometheus(file_name=file_name, prometheus_url=prometheus_url)
        logger.info_green_bg("Finished sending metrics to prometheus")
    except Exception as e:
        exit_on_error_and_write_summary(f"Error in get_acm_imported_certs: {e}")
    finally:
        logger.info(f"Removing file {file_name} after the use")
        shutil.rmtree(file_name, ignore_errors=True)


if __name__ == '__main__':
    main()
