#!/usr/bin/env python3
"""Read-only daily ONTAP health summary. Exit 1 on a warning or API error."""
import argparse
import csv
import getpass
import os
from datetime import datetime, timezone
from pathlib import Path

import requests
from requests.auth import HTTPBasicAuth
from ontap_api import inventory, records


def check(session, address, threshold):
    endpoints = {
        "nodes": "/api/cluster/nodes?fields=name,state&max_records=1000",
        "aggregates": "/api/storage/aggregates?fields=name,space.block_storage&max_records=1000",
        "volumes": "/api/storage/volumes?fields=name,svm.name,state,space&max_records=1000",
        "mirrors": "/api/snapmirror/relationships?fields=healthy,lag_time,source.path,destination.path&max_records=1000",
    }
    data = {key: list(records(session, address, endpoint)) for key, endpoint in endpoints.items()}
    warnings = []
    if not data["nodes"]:
        warnings.append("No nodes returned")
    for node in data["nodes"]:
        if node.get("state") != "up":
            warnings.append(f"Node {node.get('name')} state={node.get('state')}")
    for aggregate in data["aggregates"]:
        space = aggregate.get("space", {}).get("block_storage", {})
        size = space.get("size") or 0
        if size and space.get("used") is not None:
            percent = 100 * space["used"] / size
            if percent >= threshold:
                warnings.append(f"Aggregate {aggregate.get('name')} used={percent:.1f}%")
    for volume in data["volumes"]:
        name = f"{volume.get('svm', {}).get('name')}/{volume.get('name')}"
        if volume.get("state") != "online":
            warnings.append(f"Volume {name} state={volume.get('state')}")
        space = volume.get("space", {})
        size = space.get("size") or 0
        if size and space.get("used") is not None:
            percent = 100 * space["used"] / size
            if percent >= threshold:
                warnings.append(f"Volume {name} used={percent:.1f}%")
    for mirror in data["mirrors"]:
        if mirror.get("healthy") is False:
            warnings.append(f"SnapMirror {mirror.get('source', {}).get('path')} -> "
                            f"{mirror.get('destination', {}).get('path')} unhealthy")
    return data, warnings


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--inventory", required=True)
    parser.add_argument("--username", required=True)
    parser.add_argument("--ca-bundle", help="CA PEM file if ONTAP uses an internal CA")
    parser.add_argument("--threshold", type=int, default=85)
    parser.add_argument("--out-dir", default="reports")
    args = parser.parse_args()
    if not 1 <= args.threshold <= 99:
        parser.error("--threshold must be from 1 to 99")
    password = os.environ.get("ONTAP_PASSWORD") or getpass.getpass("ONTAP password: ")
    session = requests.Session()
    session.auth = HTTPBasicAuth(args.username, password)
    session.verify = args.ca_bundle if args.ca_bundle else True
    output = []
    for row in inventory(args.inventory):
        result = {"UTC": datetime.now(timezone.utc).isoformat(), **row}
        try:
            data, warnings = check(session, row["Address"], args.threshold)
            result.update({key.title(): len(value) for key, value in data.items()})
            result["Status"] = "WARN" if warnings else "OK"
            result["Details"] = "; ".join(warnings)
        except (requests.RequestException, ValueError, KeyError) as exc:
            result.update(Status="ERROR", Details=str(exc))
        output.append(result)
        print(f"{row['Cluster']}: {result['Status']} {result['Details']}")
    directory = Path(args.out_dir)
    directory.mkdir(parents=True, exist_ok=True)
    report = directory / f"health-{datetime.now(timezone.utc):%Y%m%dT%H%M%SZ}.csv"
    columns = ["UTC", "Cluster", "Address", "Nodes", "Aggregates", "Volumes", "Mirrors", "Status", "Details"]
    with report.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=columns)
        writer.writeheader()
        writer.writerows(output)
    print(f"Wrote {report}")
    return int(any(row["Status"] != "OK" for row in output))


if __name__ == "__main__":
    raise SystemExit(main())
