"""
service.py — Windows Service wrapper for the Scheinman Flask app.

Requirements:
    pip install pywin32
    python Scripts/pywin32_postinstall.py -install   (run once, as Administrator)

Usage (all commands must be run as Administrator):
    python web\service.py install    -- register the service
    python web\service.py start      -- start it
    python web\service.py stop       -- stop it
    python web\service.py remove     -- unregister it
    python web\service.py restart    -- restart it

The service starts automatically at boot (AUTO_START).
Logs are written to web\service.log next to this file.
"""

import sys
import os
import threading
import logging

import win32serviceutil
import win32service
import win32event
import servicemanager

# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
WEB_DIR  = os.path.join(BASE_DIR, 'web')
LOG_FILE = os.path.join(WEB_DIR, 'service.log')

# Flask app lives next to this file; scheinman module is in ../python/
sys.path.insert(0, WEB_DIR)
sys.path.insert(0, os.path.join(BASE_DIR, 'python'))


# ---------------------------------------------------------------------------
# Service class
# ---------------------------------------------------------------------------

class ScheinmanService(win32serviceutil.ServiceFramework):
    _svc_name_         = 'ScheinmanApp'
    _svc_display_name_ = 'Scheinman Boolean Minimizer'
    _svc_description_  = 'Flask web server for the Scheinman Boolean minimization tool (port 80)'
    _svc_start_type_   = win32service.SERVICE_AUTO_START

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self._stop_event = win32event.CreateEvent(None, 0, 0, None)
        self._server_thread: threading.Thread | None = None

    # ------------------------------------------------------------------
    # Service control handlers
    # ------------------------------------------------------------------

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        _log('Service stop requested')
        # Signal the wait loop to exit; Flask will be killed when the
        # daemon thread loses its last non-daemon reference (process exit).
        win32event.SetEvent(self._stop_event)

    def SvcDoRun(self):
        _setup_logging()
        servicemanager.LogMsg(
            servicemanager.EVENTLOG_INFORMATION_TYPE,
            servicemanager.PYS_SERVICE_STARTED,
            (self._svc_name_, ''),
        )
        _log('Service starting — importing Flask app')

        try:
            # Import here (not at module level) so import errors appear in the log
            from app import app as flask_app  # noqa: PLC0415

            port = int(os.environ.get('PORT', 80))
            _log(f'Binding to 0.0.0.0:{port}')

            self._server_thread = threading.Thread(
                target=flask_app.run,
                kwargs={
                    'host': '0.0.0.0',
                    'port': port,
                    'debug': False,
                    'use_reloader': False,
                    'threaded': True,
                },
                daemon=True,
                name='flask-main',
            )
            self._server_thread.start()
            _log('Flask thread started — waiting for stop signal')

        except Exception as exc:
            _log(f'FATAL: failed to start Flask: {exc}', level=logging.ERROR)
            servicemanager.LogErrorMsg(str(exc))
            self.ReportServiceStatus(win32service.SERVICE_STOPPED)
            return

        # Block until SvcStop() fires
        win32event.WaitForSingleObject(self._stop_event, win32event.INFINITE)
        _log('Service stopped')


# ---------------------------------------------------------------------------
# Logging helpers
# ---------------------------------------------------------------------------

def _setup_logging():
    logging.basicConfig(
        filename=LOG_FILE,
        level=logging.INFO,
        format='%(asctime)s %(levelname)s %(message)s',
    )


def _log(msg: str, level: int = logging.INFO):
    logging.log(level, msg)


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == '__main__':
    if len(sys.argv) == 1:
        # Called by the SCM (Service Control Manager) — hand off to pywin32
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(ScheinmanService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        # Called with install / start / stop / remove / restart
        win32serviceutil.HandleCommandLine(ScheinmanService)
