using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using System.Text.Json;
using TodoList.Application;
using TodoList.Application.DynamicApi;
using TodoList.Maui.Models;
using AppSettings = TodoList.Maui.Models.AppSettings;

namespace TodoList.Maui.Services;

public class EmbeddedWebServerService : IEmbeddedWebServerService
{
    private WebApplication? _webApp;
    private readonly AppSettings _appSettings;

    public bool IsRunning => _webApp != null;
    public string BaseUrl => _appSettings.WebServer.HostUrl;

    public EmbeddedWebServerService(AppSettings appSettings)
    {
        _appSettings = appSettings;
    }

    public async Task StartAsync()
    {
        if (_webApp != null) return;

        var builder = WebApplication.CreateSlimBuilder();

        builder.WebHost.UseUrls(_appSettings.WebServer.HostUrl);


        builder.Services.AddControllers()
            .AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
            });

        builder.Services.AddEndpointsApiExplorer();


        builder.Services.AddApplicationServices(_appSettings.WebServer.ConnectionString);

        builder.Services.AddCors(options =>
        {
            options.AddPolicy("AllowAll", policy =>
            {
                policy.AllowAnyOrigin()
                      .AllowAnyMethod()
                      .AllowAnyHeader();
            });
        });

        var app = builder.Build();

        if (_appSettings.WebServer.IsUsingStatic)
        {
            ServeStaticFiles(app);
        }

        app.UseCors("AllowAll");
        app.UseHttpsRedirection();
        app.UseAuthorization();
        app.UseDynamicApi();
        app.MapControllers();

        _webApp = app;

        await _webApp.StartAsync();
    }

    private void ServeStaticFiles(WebApplication app)
    {
        var wwwrootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot");

        if (!Directory.Exists(wwwrootPath))
        {
            Console.WriteLine("[EmbeddedWebServer] wwwroot directory not found. Static file serving disabled.");
            return;
        }

        try
        {
            var fileProvider = new PhysicalFileProvider(wwwrootPath);
            var defaultFilesOptions = new DefaultFilesOptions { FileProvider = fileProvider, RequestPath = "" };
            app.UseDefaultFiles(defaultFilesOptions);

            var staticFileOptions = new StaticFileOptions
            {
                FileProvider = fileProvider,
                RequestPath = "",
                OnPrepareResponse = ctx =>
                {
                    ctx.Context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
                    ctx.Context.Response.Headers["Pragma"] = "no-cache";
                    ctx.Context.Response.Headers["Expires"] = "0";
                }
            };
            app.UseStaticFiles(staticFileOptions);

            app.Use(async (context, next) =>
            {
                if (context.Request.Path.HasValue)
                {
                    var path = context.Request.Path.Value;
                    if (path != "/" && !path.StartsWith("/assets", StringComparison.OrdinalIgnoreCase) && !path.StartsWith("/api", StringComparison.OrdinalIgnoreCase))
                    {
                        var ext = Path.GetExtension(path);
                        if (string.IsNullOrEmpty(ext))
                        {
                            context.Request.Path = "/index.html";
                        }
                    }
                }
                await next();
            });

            Console.WriteLine($"[EmbeddedWebServer] Serving static files from: {wwwrootPath}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[EmbeddedWebServer] Failed to serve static files: {ex.Message}");
        }
    }

    public async Task StopAsync()
    {
        if (_webApp == null) return;

        await _webApp.StopAsync();
        await _webApp.DisposeAsync();
        _webApp = null;
    }
}