#!/usr/libexec/platform-python
#
# 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 argparse
import datetime
import json
import os
import shutil
import subprocess  # nosec B404
import sys
from pathlib import Path
from typing import Optional, Sequence

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 local form."""
    boot_dt = datetime.datetime.strptime(boot_time, "%Y-%m-%dT%H:%M:%S")
    return boot_dt.strftime("%Y-%m-%d %H:%M:%S")


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"Time Zone   : {report['timezone']}",
        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 get_systemctl_bin() -> Optional[str]:
    """Return the absolute path to systemctl if it is available."""
    return shutil.which("systemctl")


def run_systemctl(
    systemctl_bin: str,
    args: Sequence[str],
    check: bool = False,
) -> subprocess.CompletedProcess:
    """Run a systemctl command."""
    return subprocess.run(
        [systemctl_bin] + list(args),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        universal_newlines=True,
        check=check,
    )  # nosec B603


def show_status(systemctl_bin: str) -> int:
    """Show the status of the lastboot services."""
    all_enabled = True
    for svc in SERVICES:
        result = run_systemctl(systemctl_bin, ["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 build_parser() -> argparse.ArgumentParser:
    """Build the lastboot command line parser."""
    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",
    )
    return parser


def handle_report(output_json: bool) -> int:
    """Render the saved report in either text or JSON form."""
    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


def validate_system_access(output_json: bool) -> Optional[str]:
    """Validate prerequisites for service-management actions."""
    if output_json:
        print(
            "Error: --json is only supported as "
            "'oled lastboot report --json'.",
            file=sys.stderr,
        )
        return None

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


def reload_systemd(systemctl_bin: str) -> None:
    """Run systemctl daemon-reload."""
    subprocess.run(
        [systemctl_bin, "daemon-reload"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
        check=True,
    )  # nosec B603


def apply_action(action: str, systemctl_bin: str) -> int:
    """Enable or disable the managed lastboot services."""
    reload_systemd(systemctl_bin)

    success = []
    failed = []
    for svc in SERVICES:
        result = run_systemctl(systemctl_bin, [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


def main() -> int:
    """Run the lastboot CLI."""
    parser = build_parser()

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

    if args.action == "report":
        return handle_report(output_json)

    systemctl_bin = validate_system_access(output_json)
    if systemctl_bin is None:
        return 1

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

    return apply_action(args.action, systemctl_bin)


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