from flask import render_template, request, session
import sqlite3
from datetime import datetime, date, timedelta
import geoip2.database
from urllib.parse import urlparse, unquote

from auth import require_secret

file_access_temp = []

def lookup_location(ip, reader):
    try:
        response = reader.city(ip)
        country = response.country.name if response.country.name else "Unknown"
        city = response.city.name if response.city.name else "Unknown"
        return country, city
    except Exception:
        return "Unknown", "Unknown"

def get_device_type(user_agent):
    "classify device type based on user agent string"
    if 'Android' in user_agent:
        return 'Android'
    elif 'iPhone' in user_agent or 'iPad' in user_agent:
        return 'iOS'
    elif 'Windows' in user_agent:
        return 'Windows'
    elif 'Macintosh' in user_agent or 'Mac OS' in user_agent:
        return 'MacOS'
    elif 'Linux' in user_agent:
        return 'Linux'
    else:
        return 'Other'

def log_file_access(rel_path, ip_address, user_agent, device_id):
    """
    Log file access details to a SQLite database.
    Records the timestamp, full file path, client IP, user agent, and device_id.
    """
    global file_access_temp
    # Connect to the database (this will create the file if it doesn't exist)
    conn = sqlite3.connect('access_log.db')
    cursor = conn.cursor()
    # Create the table if it doesn't exist
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS file_access_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT,
            rel_path TEXT,
            ip_address TEXT,
            user_agent TEXT,
            device_id TEXT
        )
    ''')
    # Gather information from the request
    timestamp = datetime.now().isoformat()
    
    # Insert the access record into the database
    cursor.execute('''
        INSERT INTO file_access_log (timestamp, rel_path, ip_address, user_agent, device_id)
        VALUES (?, ?, ?, ?, ?)
    ''', (timestamp, rel_path, ip_address, user_agent, device_id))
    conn.commit()
    conn.close()
    file_access_temp.insert(0, [timestamp, rel_path, ip_address, user_agent, device_id])
    return return_file_access()

def return_file_access():
    global file_access_temp
    if len(file_access_temp) > 0:
        # Compute the cutoff time (10 minutes ago from now)
        cutoff_time = datetime.now() - timedelta(minutes=10)
        # Update the list in-place to keep only entries newer than 10 minutes
        file_access_temp[:] = [
            entry for entry in file_access_temp 
            if datetime.fromisoformat(entry[0]) >= cutoff_time
        ]
        return file_access_temp
    else:
        return []

@require_secret
def connections():
    return render_template('connections.html')

@require_secret
def dashboard():
    timeframe = request.args.get('timeframe', 'today')
    now = datetime.now()

    if timeframe == 'today':
        start = now.replace(hour=0, minute=0, second=0, microsecond=0)
    elif timeframe == '7days':
        start = now - timedelta(days=7)
    elif timeframe == '30days':
        start = now - timedelta(days=30)
    elif timeframe == '365days':
        start = now - timedelta(days=365)
    else:
        start = now.replace(hour=0, minute=0, second=0, microsecond=0)

    conn = sqlite3.connect('access_log.db')
    cursor = conn.cursor()

    # Raw file access counts for the table (top files)
    cursor.execute('''
        SELECT rel_path, COUNT(*) as access_count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY rel_path
        ORDER BY access_count DESC
        LIMIT 20
    ''', (start.isoformat(),))
    rows = cursor.fetchall()

    # Daily access trend for a line chart
    cursor.execute('''
        SELECT date(timestamp) as date, COUNT(*) as count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY date
        ORDER BY date
    ''', (start.isoformat(),))
    daily_access_data = [dict(date=row[0], count=row[1]) for row in cursor.fetchall()]

    # Top files for bar chart
    cursor.execute('''
        SELECT rel_path, COUNT(*) as access_count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY rel_path
        ORDER BY access_count DESC
        LIMIT 10
    ''', (start.isoformat(),))
    top_files_data = [dict(rel_path=row[0], access_count=row[1]) for row in cursor.fetchall()]

    # User agent distribution (aggregate by device type)
    cursor.execute('''
        SELECT user_agent, COUNT(*) as count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY user_agent
        ORDER BY count DESC
    ''', (start.isoformat(),))
    raw_user_agents = [dict(user_agent=row[0], count=row[1]) for row in cursor.fetchall()]
    device_counts = {}
    for entry in raw_user_agents:
        device = get_device_type(entry['user_agent'])
        device_counts[device] = device_counts.get(device, 0) + entry['count']
    # Rename to user_agent_data for compatibility with the frontend
    user_agent_data = [dict(device=device, count=count) for device, count in device_counts.items()]

    # Parent folder distribution
    cursor.execute('''
        SELECT rel_path, COUNT(*) as count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY rel_path
        ORDER BY count DESC
    ''', (start.isoformat(),))
    folder_data = {}
    for row in cursor.fetchall():
        rel_path = row[0]
        parent_folder = rel_path.rsplit('/', 1)[0] if '/' in rel_path else "Root"
        folder_data[parent_folder] = folder_data.get(parent_folder, 0) + row[1]
    
    # Convert the dictionary to a list of dictionaries
    folder_data = [
        dict(folder=folder, count=count) 
        for folder, count in folder_data.items()
    ]
    
    # Sort by count in descending order and take the top 10
    folder_data.sort(key=lambda x: x['count'], reverse=True)
    folder_data = folder_data[:10]

    # Aggregate IP addresses with counts
    cursor.execute('''
        SELECT ip_address, COUNT(*) as count
        FROM file_access_log
        WHERE timestamp >= ?
        GROUP BY ip_address
        ORDER BY count DESC
    ''', (start.isoformat(),))
    ip_rows = cursor.fetchall()

    # Initialize GeoIP2 reader once for efficiency
    reader = geoip2.database.Reader('GeoLite2-City.mmdb')
    location_data = {}
    for ip, count in ip_rows:
        country, city = lookup_location(ip, reader)
        key = (country, city)
        if key in location_data:
            location_data[key] += count
        else:
            location_data[key] = count
    reader.close()
    
    # Convert the dictionary to a list of dictionaries
    location_data = [
        dict(country=key[0], city=key[1], count=value) 
        for key, value in location_data.items()
    ]
    
    # Sort by count in descending order and take the top 20
    location_data.sort(key=lambda x: x['count'], reverse=True)
    location_data = location_data[:20]

    # Summary stats using separate SQL queries
    cursor.execute('SELECT COUNT(*) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
    total_accesses = cursor.fetchone()[0]
    
    # Use a separate query to count unique files (distinct rel_path values)
    cursor.execute('SELECT COUNT(DISTINCT rel_path) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
    unique_files = cursor.fetchone()[0]

    # Use a separate query to count unique IP addresses
    cursor.execute('SELECT COUNT(DISTINCT device_id) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
    unique_user = cursor.fetchone()[0]
    
    conn.close()

    return render_template("dashboard.html",
                           timeframe=timeframe,
                           rows=rows,
                           daily_access_data=daily_access_data,
                           top_files_data=top_files_data,
                           user_agent_data=user_agent_data,
                           folder_data=folder_data,
                           location_data=location_data,
                           total_accesses=total_accesses,
                           unique_files=unique_files,
                           unique_user=unique_user)