import argparse
import asyncio
import ssl
import sqlite3
import time
from datetime import datetime
from typing import List, Dict, Tuple

import httpx


async def check_http_endpoint(url: str, timeout: float) -> Tuple[bool, str]:
    """
    Checks if an HTTP endpoint is reachable and returns a success status and message.

    Args:
        url: The URL of the endpoint to check.
        timeout: The timeout in seconds for the request.

    Returns:
        A tuple containing a boolean indicating success (True) or failure (False)
        and a message describing the result.
    """
    try:
        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.get(url)
            response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
            return True, f"HTTP {url} check passed (Status code: {response.status_code})"
    except httpx.HTTPError as e:
        return False, f"HTTP {url} check failed: {e}"
    except httpx.TimeoutError:
        return False, f"HTTP {url} check failed: Timeout"
    except Exception as e:
        return False, f"HTTP {url} check failed: {e}"


async def check_ssl_cert(url: str, timeout: float) -> Tuple[bool, str]:
    """
    Checks the SSL certificate of a given URL.

    Args:
        url: The URL to check the SSL certificate for.
        timeout: The timeout in seconds for the connection.

    Returns:
        A tuple containing a boolean indicating success (True) or failure (False)
        and a message describing the result.
    """
    try:
        context = ssl.create_default_context()
        with httpx.Client(endpoint=url, verify=True, timeout=timeout) as client:
            response = client.get(url)
            response.raise_for_status()
            cert = response.cert
            if cert:
                return True, f"SSL certificate check for {url} passed"
            else:
                return False, f"SSL certificate check for {url} failed: No certificate found"
    except ssl.SSLError as e:
        return False, f"SSL certificate check for {url} failed: {e}"
    except httpx.HTTPError as e:
        return False, f"SSL certificate check for {url} failed: {e}"
    except httpx.TimeoutError:
        return False, f"SSL certificate check for {url} failed: Timeout"
    except Exception as e:
        return False, f"SSL certificate check for {url} failed: {e}"


def check_dns_record(domain: str, record_type: str) -> Tuple[bool, str]:
    """
    Checks for a specific DNS record type for a given domain.

    Args:
        domain: The domain name to check.
        record_type: The type of DNS record to look for (e.g., A, CNAME).

    Returns:
        A tuple containing a boolean indicating success (True) or failure (False)
        and a message describing the result.
    """
    try:
        import dns.resolver
        resolver = dns.resolver.Resolver()
        resolver.timeout = 5
        resolver.lifetime = 5
        answers = resolver.resolve(domain, record_type)
        return True, f"DNS {record_type} record check for {domain} passed: {answers}"
    except dns.resolver.NXDOMAIN:
        return False, f"DNS {record_type} record check for {domain} failed: Domain not found"
    except dns.resolver.NoAnswer:
        return False, f"DNS {record_type} record check for {domain} failed: No record found"
    except dns.resolver.Timeout:
        return False, f"DNS {record_type} record check for {domain} failed: Timeout"
    except Exception as e:
        return False, f"DNS {record_type} record check for {domain} failed: {e}"


async def check_response_time(url: str, timeout: float) -> Tuple[bool, str]:
    """
    Checks the response time of an HTTP endpoint.

    Args:
        url: The URL of the endpoint to check.
        timeout: The timeout in seconds for the request.

    Returns:
        A tuple containing a boolean indicating success (True) or failure (False)
        and a message describing the result.
    """
    try:
        start_time = time.time()
        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.get(url)
            response.raise_for_status()
        end_time = time.time()
        response_time = end_time - start_time
        return True, f"Response time check for {url} passed: {response_time:.2f} seconds"
    except httpx.HTTPError as e:
        return False, f"Response time check for {url} failed: {e}"
    except httpx.TimeoutError:
        return False, f"Response time check for {url} failed: Timeout"
    except Exception as e:
        return False, f"Response time check for {url} failed: {e}"


def store_results(results: List[Tuple[str, bool, str]], db_name: str) -> None:
    """
    Stores the deployment check results in a SQLite database.

    Args:
        results: A list of tuples, where each tuple contains the check name,
                 a boolean indicating success/failure, and a message.
        db_name: The name of the SQLite database file.
    """
    conn = sqlite3.connect(db_name)
    cursor = conn.cursor()

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS deployment_checks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
            check_name TEXT,
            passed BOOLEAN,
            message TEXT
        )
    """)

    for check_name, passed, message in results:
        cursor.execute(
            "INSERT INTO deployment_checks (check_name, passed, message) VALUES (?, ?, ?)",
            (check_name, passed, message),
        )

    conn.commit()
    conn.close()


async def main(args: argparse.Namespace) -> None:
    """
    Main function to run the deployment checks.
    """
    results: List[Tuple[str, bool, str]] = []

    for check in args.checks:
        check_type, check_value = check.split(":", 1)

        if check_type == "http":
            success, message = await check_http_endpoint(check_value, args.timeout)
            results.append((f"HTTP Check: {check_value}", success, message))
        elif check_type == "ssl":
            success, message = await check_ssl_cert(check_value, args.timeout)
            results.append((f"SSL Check: {check_value}", success, message))
        elif check_type == "dns":
            record_type = args.dns_record_type if args.dns_record_type else "A"
            success, message = check_dns_record(check_value, record_type)
            results.append((f"DNS Check ({record_type}): {check_value}", success, message))
        elif check_type == "response_time":
            success, message = await check_response_time(check_value, args.timeout)
            results.append((f"Response Time Check: {check_value}", success, message))
        else:
            print(f"Unknown check type: {check_type}")

    print("\n--- Deployment Check Report ---")
    for check_name, passed, message in results:
        print(f"{check_name}: {'Pass' if passed else 'Fail'} - {message}")

    if args.db_name:
        store_results(results, args.db_name)
        print(f"\nResults stored in database: {args.db_name}")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Deployment Checker")
    parser.add_argument(
        "--checks",
        nargs="+",
        required=True,
        help="List of checks to perform (e.g., http:https://example.com ssl:https://example.com dns:example.com response_time:https://example.com)",
    )
    parser.add_argument(
        "--timeout", type=float, default=10.0, help="Timeout in seconds for HTTP/SSL checks (default: 10.0)"
    )
    parser.add_argument(
        "--dns_record_type",
        type=str,
        help="DNS record type to check (e.g., A, CNAME). Defaults to A if not specified.",
    )
    parser.add_argument(
        "--db_name", type=str, help="Name of the SQLite database to store results (optional)"
    )

    args = parser.parse_args()

    asyncio.run(main(args))