"""
collector.py
يجمع مقاييس مراقبة لموقع mithal.space كل دقيقة ويخزنها في CSV و JSON:
  - Latency: زمن استجابة HTTP
  - Uptime: هل الموقع متاح (status code)
  - SSL: حالة الشهادة وتاريخ انتهائها
  - DNS: وقت تحليل DNS
  - Search Response: زمن الرد على عملية بحث (query) داخل الموقع

الاستخدام:
    python collector.py                # يعمل باستمرار كل 60 ثانية
    python collector.py --once         # فحص واحد فقط (مفيد للاختبار / cron)
"""

import argparse
import csv
import json
import socket
import ssl
import time
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse

import requests

TARGET_URL = "https://mithal.space"
# عدّل هذا لمسار بحث فعلي في الموقع لو مختلف
SEARCH_URL = "https://mithal.space/search?q=test"

CSV_FILE = Path("metrics.csv")
JSON_FILE = Path("latest.json")
HISTORY_JSON = Path("history.json")
CHECK_INTERVAL = 60  # ثانية
HISTORY_MAX = 1440   # الاحتفاظ بآخر 24 ساعة (فحص كل دقيقة)


def check_dns(hostname: str) -> float:
    """يقيس وقت تحليل DNS بالمللي ثانية."""
    start = time.perf_counter()
    try:
        socket.gethostbyname(hostname)
        return round((time.perf_counter() - start) * 1000, 2)
    except socket.gaierror:
        return -1.0


def check_http(url: str) -> dict:
    """يقيس زمن الاستجابة وكود الحالة."""
    try:
        start = time.perf_counter()
        resp = requests.get(url, timeout=10)
        elapsed_ms = round((time.perf_counter() - start) * 1000, 2)
        return {"status_code": resp.status_code, "latency_ms": elapsed_ms, "up": resp.status_code < 400}
    except requests.RequestException as e:
        return {"status_code": None, "latency_ms": -1, "up": False, "error": str(e)}


def check_ssl(hostname: str, port: int = 443) -> dict:
    """يفحص حالة شهادة SSL وعدد الأيام المتبقية على انتهائها."""
    try:
        ctx = ssl.create_default_context()
        with socket.create_connection((hostname, port), timeout=10) as sock:
            with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
                cert = ssock.getpeercert()
        expiry = datetime.strptime(cert["notAfter"], "%b %d %H:%M:%S %Y %Z")
        expiry = expiry.replace(tzinfo=timezone.utc)
        days_left = (expiry - datetime.now(timezone.utc)).days
        return {"valid": True, "expires_on": expiry.isoformat(), "days_left": days_left}
    except Exception as e:
        return {"valid": False, "error": str(e)}


def check_search(url: str) -> dict:
    """يرسل طلب بحث ويقيس زمن الرد."""
    try:
        start = time.perf_counter()
        resp = requests.get(url, timeout=10)
        elapsed_ms = round((time.perf_counter() - start) * 1000, 2)
        return {"status_code": resp.status_code, "latency_ms": elapsed_ms}
    except requests.RequestException as e:
        return {"status_code": None, "latency_ms": -1, "error": str(e)}


def run_check() -> dict:
    hostname = urlparse(TARGET_URL).hostname
    timestamp = datetime.now(timezone.utc).isoformat()

    http_result = check_http(TARGET_URL)
    dns_ms = check_dns(hostname)
    ssl_result = check_ssl(hostname)
    search_result = check_search(SEARCH_URL)

    return {
        "timestamp": timestamp,
        "up": http_result.get("up", False),
        "status_code": http_result.get("status_code"),
        "latency_ms": http_result.get("latency_ms"),
        "dns_ms": dns_ms,
        "ssl_valid": ssl_result.get("valid"),
        "ssl_days_left": ssl_result.get("days_left"),
        "search_latency_ms": search_result.get("latency_ms"),
    }


def append_csv(row: dict):
    is_new = not CSV_FILE.exists()
    with open(CSV_FILE, "a", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=list(row.keys()))
        if is_new:
            writer.writeheader()
        writer.writerow(row)


def update_json(row: dict):
    # أحدث قراءة (يقرأها الـ dashboard مباشرة)
    JSON_FILE.write_text(json.dumps(row, ensure_ascii=False, indent=2), encoding="utf-8")

    # سجل تاريخي محدود (لآخر 24 ساعة) يستخدمه الـ dashboard للرسم البياني والجدول
    history = []
    if HISTORY_JSON.exists():
        try:
            history = json.loads(HISTORY_JSON.read_text(encoding="utf-8"))
        except json.JSONDecodeError:
            history = []
    history.append(row)
    history = history[-HISTORY_MAX:]
    HISTORY_JSON.write_text(json.dumps(history, ensure_ascii=False, indent=2), encoding="utf-8")


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--once", action="store_true", help="تشغيل فحص واحد فقط ثم الخروج")
    args = parser.parse_args()

    while True:
        row = run_check()
        append_csv(row)
        update_json(row)
        print(f"[{row['timestamp']}] up={row['up']} latency={row['latency_ms']}ms "
              f"dns={row['dns_ms']}ms ssl_days_left={row['ssl_days_left']} "
              f"search={row['search_latency_ms']}ms")

        if args.once:
            break
        time.sleep(CHECK_INTERVAL)


if __name__ == "__main__":
    main()
