using Ninject;
using Inspectron.Epson.PrintServer;
using Inspectron.Epson.PrintServer.ConfigurationSources;
using Inspectron.Epson.PrintServer.JobSources;
using Inspectron.Epson.PrintServer.Printers;
using Inspectron.Epson.PrintServer.PrintServices;
using Microsoft.Extensions.Logging;

namespace ConfigurationPannel.Services;

public class PrintServerHostedService : IHostedService
{
    private readonly ILogger<PrintServerHostedService> _logger;
    private readonly ConfigurationManager _configManager;
    private PrintServer? _printServer;
    private PrintLoop? _printLoop;
    private StandardKernel? _kernel;

    public PrintServerHostedService(
        ILogger<PrintServerHostedService> logger,
        ConfigurationManager configManager)
    {
        _logger = logger;
        _configManager = configManager;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Starting PrintServer background service");
        await InitializePrintServerAsync();
    }

    private async Task InitializePrintServerAsync()
    {
        // Load configuration
        var config = await _configManager.LoadConfigurationAsync();

        // Setup Ninject kernel (matching EpsonPrintService pattern)
        _kernel = new StandardKernel();
        _kernel.Bind<EpsonPrintServiceConfiguration>().ToConstant(config);
        _kernel.Bind<IPrintJobSource>().To<SignalRPrintJobSource>().InSingletonScope();
        _kernel.Bind<IPrintService>().To<Inspectron.Epson.PrintServer.PrintServices.EpsonPrintService>();
        _kernel.Bind<Microsoft.Extensions.Logging.ILogger>().ToConstant(_logger);
        _kernel.Bind<IAssignedPrinterRepository>().ToConstant(config);
        _kernel.Bind<IWrapperPrinterFactory>().To<PrinterWrapperFactory>().InSingletonScope();
        _kernel.Bind<IPrinterConfigurationSource>().ToConstant(config);
        _kernel.Bind<IJobStatusReporter>().To<NullJobStatusReporter>();
        _kernel.Bind<PrintServer>().ToSelf().InSingletonScope();

        // Get instances
        _printServer = _kernel.Get<PrintServer>();
        _printLoop = _kernel.Get<PrintLoop>();

        // Register printers from configuration
        foreach (var printerConfig in config.PrinterConfigurations.Values)
        {
            _printServer.RegisterPrinter(printerConfig.Address);
        }

        // Start print loop
        await _printLoop.StartAsync();
        _logger.LogInformation("PrintServer background service started successfully");
    }

    public async Task RestartAsync()
    {
        _logger.LogInformation("Restarting PrintServer with new configuration");

        // Stop current print loop
        if (_printLoop != null)
        {
            await _printLoop.StopAsync();
        }

        // Shutdown print server
        if (_printServer != null)
        {
            await _printServer.ShutdownAsync();
        }

        // Dispose kernel
        _kernel?.Dispose();

        // Reinitialize with new config
        await InitializePrintServerAsync();

        _logger.LogInformation("PrintServer background service restarted successfully");
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Stopping PrintServer background service");

        if (_printLoop != null)
        {
            await _printLoop.StopAsync();
        }

        if (_printServer != null)
        {
            await _printServer.ShutdownAsync();
        }

        _kernel?.Dispose();

        _logger.LogInformation("PrintServer background service stopped");
    }

    public async Task<(bool Success, string Message)> SubmitPrintJobAsync(string workAreaId, string content)
    {
        if (_printServer == null)
            return (false, "Print server not initialized");

        var config = await _configManager.LoadConfigurationAsync();
        var printerIp = config.GetAssignedPrinter(workAreaId);

        if (string.IsNullOrEmpty(printerIp))
            return (false, "No printer assigned to this work area");

        var job = new PrintJob
        {
            AreaId = workAreaId,
            Document = content
        };

        _printServer.SubmitJob(printerIp, job);
        _logger.LogInformation($"Test print job submitted to {printerIp} for work area {workAreaId}");

        return (true, $"Print job submitted successfully to {printerIp}");
    }
}
