import argparse
import datetime
import sqlite3
import re
from collections import Counter
import httpx

def parse_nginx_log_line(log_line: str) -> dict | None:
    """
    Parses a single line from an nginx access log.

    Args:
        log_line: A string representing a single log line.

    Returns:
        A dictionary containing parsed log data, or None if parsing fails.
    """
    try:
        pattern = r'(\S+) - - \[([^\]]+)\] "(\S+) (\S+) (\S+)" (\d+) (\d+) "([^"]+)" "([^"]+)"'
        match = re.match(pattern, log_line)
        if match:
            return {
                'remote_addr': match.group(1),
                'timestamp': datetime.datetime.strptime(match.group(2), '%d/%b/%Y:%H:%M:%S %z'),
                'method': match.group(3),
                'endpoint': match.group(4),
                'protocol': match.group(5),
                'status_code': int(match.group(6)),
                'body_bytes_sent': int(match.group(7)),
                'referrer': match.group(8),
                'user_agent': match.group(9)
            }
        else:
            return None
    except ValueError:
        return None

def parse_systemd_log_line(log_line: str) -> dict | None:
    """
    Parses a single line from a systemd journal log (simplified).

    Args:
        log_line: A string representing a single log line.

    Returns:
        A dictionary containing parsed log data, or None if parsing fails.
    """
    try:
        pattern = r'(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?\w+) (\w+) (\w+): (.*)'
        match = re.match(pattern, log_line)
        if match:
            return {
                'timestamp': datetime.datetime.fromisoformat(match.group(1)),
                'priority': match.group(2),
                'unit': match.group(3),
                'message': match.group(4)
            }
        else:
            return None
    except ValueError:
        return None

def create_database(db_path: str) -> None:
    """
    Creates the SQLite database and table if they don't exist.

    Args:
        db_path: The path to the SQLite database file.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS logs (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            log_type TEXT NOT NULL,
            timestamp DATETIME,
            data TEXT
        )
    """)
    conn.commit()
    conn.close()

def insert_log_entry(db_path: str, log_type: str, timestamp: datetime.datetime, data: dict) -> None:
    """
    Inserts a single log entry into the database.

    Args:
        db_path: The path to the SQLite database file.
        log_type: The type of log (e.g., 'nginx', 'systemd').
        timestamp: The timestamp of the log entry.
        data: A dictionary containing the log data.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("""
        INSERT INTO logs (log_type, timestamp, data)
        VALUES (?, ?, ?)
    """, (log_type, timestamp.isoformat(), str(data)))
    conn.commit()
    conn.close()

def analyze_logs(db_path: str) -> dict:
    """
    Analyzes the logs in the database and generates a dashboard.

    Args:
        db_path: The path to the SQLite database file.

    Returns:
        A dictionary containing the dashboard data.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    # Top endpoints (nginx only)
    cursor.execute("""
        SELECT endpoint, COUNT(*) AS count
        FROM logs
        WHERE log_type = 'nginx'
        GROUP BY endpoint
        ORDER BY count DESC
        LIMIT 10
    """)
    top_endpoints = cursor.fetchall()

    # Error rates (nginx only)
    cursor.execute("""
        SELECT SUM(CASE WHEN status_code >= 400 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS error_rate
        FROM logs
        WHERE log_type = 'nginx'
    """)
    error_rate = cursor.fetchone()[0] or 0.0

    # Average response time (nginx only - simplistic approximation)
    cursor.execute("""
        SELECT AVG(body_bytes_sent)
        FROM logs
        WHERE log_type = 'nginx'
    """)
    avg_response_time = cursor.fetchone()[0] or 0.0

    # Geographic distribution (using remote_addr - simplistic)
    cursor.execute("""
        SELECT SUBSTR(remote_addr, 1, INSTR(remote_addr, '.') - 1) AS country, COUNT(*) AS count
        FROM logs
        WHERE log_type = 'nginx'
        GROUP BY country
        ORDER BY count DESC
        LIMIT 10
    """)
    geographic_distribution = cursor.fetchall()

    conn.close()

    return {
        'top_endpoints': top_endpoints,
        'error_rate': error_rate,
        'avg_response_time': avg_response_time,
        'geographic_distribution': geographic_distribution
    }

def main() -> None:
    """
    Main function to parse logs, store them in a database, and generate a dashboard.
    """
    parser = argparse.ArgumentParser(description='Log Analyzer')
    parser.add_argument('log_files', nargs='+', help='Path(s) to the log file(s)')
    parser.add_argument('--db_path', default='logs.db', help='Path to the SQLite database file')
    args = parser.parse_args()

    create_database(args.db_path)

    for log_file in args.log_files:
        try:
            with open(log_file, 'r') as f:
                for line in f:
                    line = line.strip()
                    if not line:
                        continue

                    nginx_log = parse_nginx_log_line(line)
                    if nginx_log:
                        insert_log_entry(args.db_path, 'nginx', nginx_log['timestamp'], nginx_log)
                        continue

                    systemd_log = parse_systemd_log_line(line)
                    if systemd_log:
                        insert_log_entry(args.db_path, 'systemd', systemd_log['timestamp'], systemd_log)
                        continue

                    print(f"Warning: Could not parse log line: {line}")

        except FileNotFoundError:
            print(f"Error: Log file not found: {log_file}")
        except Exception as e:
            print(f"Error processing log file {log_file}: {e}")

    dashboard = analyze_logs(args.db_path)

    print("Dashboard:")
    print("\nTop Endpoints:")
    for endpoint, count in dashboard['top_endpoints']:
        print(f"  {endpoint}: {count}")

    print(f"\nError Rate: {dashboard['error_rate']:.2f}%")
    print(f"Average Response Time: {dashboard['avg_response_time']:.2f} bytes")

    print("\nGeographic Distribution:")
    for country, count in dashboard['geographic_distribution']:
        print(f"  {country}: {count}")

if __name__ == '__main__':
    main()