#!/usr/bin/env python3

import sys
import time
import argparse
import requests
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import pytz
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# ── Configuration ─────────────────────────────────────────────────────────────

IST = pytz.timezone("Asia/Kolkata")

NETDATA_PORT = "19999"
FETCH_TIMEOUT = 4

LOAD_SERVERS = [
    ("Db server",         "10.40.180.6"),
    ("Web server",        "10.40.180.9"),
    ("Storage 15 server", "10.40.180.15"),
    ("Mcube 10 server",   "10.40.180.10"),
    ("Mcube 12 server",   "10.40.180.12"),
    ("35 server",         "10.40.180.35"),
    ("36 server",         "10.40.180.36"),
    ("37 server",         "10.40.180.37"),
    ("38 server",         "10.40.180.38"),
    ("4 server",          "10.40.180.4"),
]

PHPFPM_LABEL = "Php fpm connections"
PHPFPM_IP = "10.40.180.9"

# ── Helpers ───────────────────────────────────────────────────────────────────

def now_ist():
    return datetime.now(IST).strftime("%Y-%m-%d %H:%M IST")

# ── Fetch Server Load ─────────────────────────────────────────────────────────

def fetch_load(ip):

    for after in ("-2", "-1"):

        try:

            r = requests.get(
                f"http://{ip}:{NETDATA_PORT}/api/v1/data"
                f"?chart=system.load&after={after}&before=0&points=1&group=average",
                timeout=FETCH_TIMEOUT,
                verify=False
            )

            if r.status_code != 200:
                continue

            data = r.json()

            if not data.get("data"):
                continue

            pt = data["data"][-1]

            if len(pt) > 1 and pt[1] is not None:
                return round(float(pt[1]), 2)

        except Exception:
            continue

    return None

# ── Fetch PHP-FPM ─────────────────────────────────────────────────────────────

def fetch_phpfpm(ip):

    for chart in ("phpfpm_local.connections", "phpfpm.connections"):

        for after in ("-1", "-2"):

            try:

                r = requests.get(
                    f"http://{ip}:{NETDATA_PORT}/api/v1/data"
                    f"?chart={chart}&after={after}&before=0&points=1&group=average",
                    timeout=FETCH_TIMEOUT,
                    verify=False
                )

                if r.status_code != 200:
                    continue

                data = r.json()

                if not data.get("data"):
                    continue

                pt = data["data"][-1]

                if len(pt) > 1 and pt[1] is not None:
                    return round(float(pt[1]), 1)

            except Exception:
                continue

    return None

# ── Fetch Asterisk Calls ──────────────────────────────────────────────────────

def fetch_asterisk_calls():

    result = {
        "classic": 0,
        "mcube2": 0,
        "total": 0,
        "error": None
    }

    try:

        url = "https://mcube.vmc.in/php_test.php"

        r = requests.get(
            url,
            timeout=10,
            verify=False
        )

        if r.status_code != 200:
            result["error"] = f"HTTP {r.status_code}"
            return result

        servers = r.json()

        classic = 0
        mcube2 = 0

        for srv in servers:

            calls = str(srv.get("calls", "0")).strip()

            app = str(srv.get("app", "")).strip().lower()

            if not calls.isdigit():
                continue

            calls = int(calls)

            if "classic" in app:
                classic += calls
            else:
                mcube2 += calls

        result["classic"] = classic
        result["mcube2"] = mcube2
        result["total"] = classic + mcube2

    except Exception as e:

        result["error"] = str(e)

    return result

# ── WhatsApp API ──────────────────────────────────────────────────────────────
def send_whatsapp_report(data):

    url = "https://rengage.mcube.com/api/wpbox/sendtemplatemessage"

    headers = {
        "Authorization": "Bearer qQeadvQxP50ES5p9OPBgQYRIEObJPprFeGzHuVob32de7dd4",
        "Content-Type": "application/json"
    }

    phones = [
        "7259803108",
        "9311529963",
        "8778858451",
        "8880222333"
    ]

    ast = data.get("__asterisk__", {})

    values = [

        str(data.get("Db server", "N/A")),
        str(data.get("Web server", "N/A")),
        str(data.get("Storage 15 server", "N/A")),
        str(data.get("Mcube 10 server", "N/A")),
        str(data.get("Mcube 12 server", "N/A")),
        str(data.get("35 server", "N/A")),
        str(data.get("36 server", "N/A")),
        str(data.get("37 server", "N/A")),
        str(data.get("38 server", "N/A")),
        str(data.get("4 server", "N/A")),
        str(data.get("Php fpm connections", "N/A")),
        str(ast.get("classic", 0)),
        str(ast.get("mcube2", 0)),
        str(ast.get("total", 0))
    ]

    parameters = []

    for val in values:

        parameters.append({
            "type": "text",
            "text": val
        })

    for phone in phones:

        payload = {

            "phone": phone,
            "country_code": "91",
            "template_name": "l1_team",
            "template_language": "en_US",

            "components": [
                {
                    "type": "body",
                    "parameters": parameters
                }
            ]
        }

        try:

            r = requests.post(
                url,
                headers=headers,
                json=payload,
                timeout=15
            )

            print(f"{phone} -> WhatsApp API Status: {r.status_code}")

            try:
                print(r.json())

            except Exception:
                print(r.text)

        except Exception as e:

            print(f"{phone} -> WhatsApp API Error: {e}")

# ── Collect All Metrics ───────────────────────────────────────────────────────

def collect_all():

    results = {}

    with ThreadPoolExecutor(max_workers=16) as ex:

        load_futures = {
            ex.submit(fetch_load, ip): label
            for label, ip in LOAD_SERVERS
        }

        phpfpm_future = ex.submit(fetch_phpfpm, PHPFPM_IP)

        ast_future = ex.submit(fetch_asterisk_calls)

        for fut, label in load_futures.items():

            try:
                results[label] = fut.result()

            except Exception:
                results[label] = None

        try:
            results[PHPFPM_LABEL] = phpfpm_future.result()

        except Exception:
            results[PHPFPM_LABEL] = None

        try:
            results["__asterisk__"] = ast_future.result()

        except Exception:

            results["__asterisk__"] = {
                "classic": 0,
                "mcube2": 0,
                "total": 0,
                "error": "fetch failed"
            }

    return results

# ── Optional Terminal Report ──────────────────────────────────────────────────

def build_report(data):

    ast = data.get("__asterisk__", {})

    lines = []

    lines.append(f"Hourly Monitoring Report - {now_ist()}")

    lines.append("=" * 45)

    lines.append("")

    lines.append("Server Load (load1)")

    lines.append("-" * 30)

    for label, _ in LOAD_SERVERS:

        val = data.get(label)

        lines.append(f"  {label:<22}: {val if val is not None else 'N/A'}")

    lines.append("")

    lines.append("PHP-FPM")

    lines.append("-" * 30)

    php_val = data.get(PHPFPM_LABEL)

    lines.append(f"  {PHPFPM_LABEL:<22}: {php_val if php_val is not None else 'N/A'}")

    lines.append("")

    lines.append("Asterisk Active Calls")

    lines.append("-" * 30)

    if ast.get("error"):

        lines.append(f"  Error: {ast['error']}")

    else:

        lines.append(f"  {'Classic calls':<22}: {ast.get('classic', 0)}")

        lines.append(f"  {'Mcube 2.0 calls':<22}: {ast.get('mcube2', 0)}")

        lines.append(f"  {'Total calls':<22}: {ast.get('total', 0)}")

    lines.append("")

    lines.append("=" * 45)

    return "\n".join(lines)

# ── Main ──────────────────────────────────────────────────────────────────────

def run_once():

    print(f"[{now_ist()}] Collecting metrics...", file=sys.stderr)

    t0 = time.time()

    data = collect_all()

    elapsed = round(time.time() - t0, 2)

    print(f"[{now_ist()}] Done in {elapsed}s", file=sys.stderr)

    print(build_report(data))

    send_whatsapp_report(data)

def main():

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--loop",
        action="store_true",
        help="Run automatically every hour"
    )

    args = parser.parse_args()

    if args.loop:

        print(
            f"[{now_ist()}] Starting hourly loop. Press Ctrl+C to stop.",
            file=sys.stderr
        )

        while True:

            run_once()

            print(
                f"[{now_ist()}] Next run in 60 minutes...\n",
                file=sys.stderr
            )

            time.sleep(3600)

    else:

        run_once()

if __name__ == "__main__":
    main()
