#!/usr/bin/python3
#
# Copyright (c) 2026, Oracle and/or its affiliates.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, see <https://www.gnu.org/licenses/>.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.

"""
Enable or disable OLED lastboot report systemd services.
"""

import sys
import os
import shutil
import subprocess
import argparse
import json
import datetime
from pathlib import Path

REPORT_DIR = Path("/var/oled/lastboot-report")

SERVICES = [
    "oled_lastboot_report.service",
]


def get_latest_report_path() -> Path:
    """Return the most recent saved lastboot report path."""
    report_paths = sorted(REPORT_DIR.glob("boot_report_*.json"), reverse=True)
    if not report_paths:
        raise FileNotFoundError("No saved last boot report found.")
    return report_paths[0]


def load_saved_report() -> dict:
    """Load and return the most recent saved lastboot report."""
    report_path = get_latest_report_path()
    with open(report_path, "r", encoding="utf-8") as report_file:
        return json.load(report_file)


def format_boot_time_text(boot_time: str) -> str:
    """Convert saved JSON boot time to human-readable UTC form."""
    boot_dt = datetime.datetime.strptime(boot_time, "%Y-%m-%dT%H:%M:%SZ")
    return boot_dt.strftime("%Y-%m-%d %H:%M:%S UTC")


def render_saved_report_text(report: dict) -> str:
    """Render the human-readable report from a saved JSON report."""
    reboot = report["reboot"]
    crash_dump = report["crash_dump"]

    if reboot["type"] == "graceful":
        status = "Graceful reboot"
    elif reboot["kernel_crash"]:
        status = "Kernel crash"
    else:
        status = "Unexpected reboot"

    lines = [
        "OLED Last Boot Report",
        "=" * 21,
        "",
        f"Host        : {report['host']}",
        f"Boot Time   : {format_boot_time_text(report['boot_time'])}",
        f"Status      : {status}",
    ]

    if reboot["type"] == "graceful":
        lines.extend(["", "No action required."])
        return "\n".join(lines) + "\n"

    if reboot["kernel_crash"] and crash_dump["vmcore_path"]:
        lines.append(f"Crash Dump  : {crash_dump['vmcore_path']}")
    else:
        lines.append("Crash Dump  : Not found")

    if report["recommended_actions"]:
        lines.extend(["", "Recommended Actions", "-------------------"])
        lines.extend(f"- {action}" for action in report["recommended_actions"])

    return "\n".join(lines) + "\n"


def run_systemctl(args, check=False) -> subprocess.CompletedProcess:
    """
    Run a systemctl command.
    """
    return subprocess.run(
        ["systemctl"] + args,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        universal_newlines=True,
        check=check,
    )


def show_status() -> int:
    """
    Show the status of the lastboot services.
    """
    all_enabled = True
    for svc in SERVICES:
        result = run_systemctl(["is-enabled", svc])
        is_enabled = result.returncode == 0
        status_str = "enabled" if is_enabled else "disabled"
        print(f"{svc}: {status_str}")
        if not is_enabled:
            all_enabled = False
    return 0 if all_enabled else 1


def main() -> int:
    parser = argparse.ArgumentParser(
        prog="lastboot",
        description="Enable or disable OLED lastboot report systemd services",
    )
    subparsers = parser.add_subparsers(dest="action")
    subparsers.required = True

    subparsers.add_parser("enable", help="Enable lastboot services")
    subparsers.add_parser("disable", help="Disable lastboot services")
    subparsers.add_parser("status", help="Show lastboot service status")

    report_parser = subparsers.add_parser(
        "report",
        help="Show the most recent saved lastboot report",
    )
    report_parser.add_argument(
        "--json",
        action="store_true",
        help="Print the saved report as JSON",
    )

    args = parser.parse_args()
    output_json = getattr(args, "json", False)

    if args.action == "report":
        try:
            report = load_saved_report()
            if output_json:
                print(json.dumps(report, indent=2))
            else:
                print(render_saved_report_text(report), end="")
            return 0
        except Exception as err:  # pylint: disable=broad-exception-caught
            print(
                f"Error generating last boot report: {err}",
                file=sys.stderr,
            )
            return 1

    if output_json:
        print(
            "Error: --json is only supported as "
            "'oled lastboot report --json'.",
            file=sys.stderr,
        )
        return 1

    if shutil.which("systemctl") is None:
        print("Error: systemctl not found.", file=sys.stderr)
        return 1
    if hasattr(os, "geteuid") and os.geteuid() != 0:
        print("Error: must be run as root.", file=sys.stderr)
        return 1

    if args.action == "status":
        return show_status()

    # daemon-reload
    subprocess.run(
        ["systemctl", "daemon-reload"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
        check=True,
    )

    action = args.action

    success = []
    failed = []
    for svc in SERVICES:
        result = run_systemctl(
            [action, svc]
        )
        if result.returncode == 0:
            success.append(svc)
        else:
            failed.append(svc)

    if success:
        verb = "Enabled" if action == "enable" else "Disabled"
        print(f"{verb} services:")
        for svc in success:
            print(f" - {svc}")

    if failed:
        print(f"Failed to {action} the following services:", file=sys.stderr)
        for svc in failed:
            print(f" - {svc}", file=sys.stderr)

    return 0 if not failed else 1


if __name__ == "__main__":
    sys.exit(main())
