using Hc900Crawler.Core.Application.Interfaces;
using Hc900Crawler.Core.Application.Services;
using Hc900Crawler.Infrastructure.Database;
using Hc900Crawler.Web;
using Hc900Crawler.Infrastructure.Hc900;
using Hc900Crawler.Infrastructure.Kb;
using Hc900Crawler.Infrastructure.Mcp;
using Hc900Crawler.Infrastructure.Trend;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// ── MVC / Swagger ─────────────────────────────────────────────────────────────
var mvcBuilder = builder.Services.AddControllers()
    .AddJsonOptions(opt =>
    {
        opt.JsonSerializerOptions.PropertyNamingPolicy = null;
        opt.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
    });
builder.Services.AddMemoryCache();

bool pidEnabled = builder.Configuration.GetValue<bool>("PidControllers:Enabled");
if (!pidEnabled)
{
    var partManager = mvcBuilder.PartManager;
    var excludedNames = new[] { "PidController", "PidGraphController" };
    var existingProvider = partManager.FeatureProviders
        .OfType<Microsoft.AspNetCore.Mvc.Controllers.ControllerFeatureProvider>()
        .FirstOrDefault();
    if (existingProvider != null)
    {
        partManager.FeatureProviders.Remove(existingProvider);
        partManager.FeatureProviders.Add(new ExcludedControllersFeatureProvider(existingProvider, excludedNames));
    }
}

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
    c.SwaggerDoc("v1", new() { Title = "HC900Crawler API", Version = "v1" }));

// ── HC900 gRPC 설정 ───────────────────────────────────────────────────────────
builder.Services.Configure<Hc900Options>(builder.Configuration.GetSection("Hc900"));

// ── PostgreSQL (hc900 schema) ─────────────────────────────────────────────────
Directory.CreateDirectory("data");
builder.Services.AddDbContext<Hc900DbContext>(opt =>
    opt.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<IExperionDbService, Hc900DbService>();
builder.Services.AddScoped<ITrendService, TrendService>();
builder.Services.AddDbContextFactory<Hc900DbContext>();

// ── HC900 게이트웨이 프로세스 관리 (N-Controller) ─────────────────────────────
builder.Services.AddSingleton<ControllerProcessManager>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<ControllerProcessManager>());

// ── HC900 gRPC 클라이언트 풀 (N-Controller) ───────────────────────────────────
builder.Services.AddSingleton<ControllerGrpcClientPool>();
builder.Services.AddSingleton<Hc900WriteService>();

// ── HC900 BackgroundServices ──────────────────────────────────────────────────
builder.Services.AddSingleton<Hc900RealtimeService>();
builder.Services.AddSingleton<IHc900RealtimeService>(sp => sp.GetRequiredService<Hc900RealtimeService>());
builder.Services.AddHostedService(sp => sp.GetRequiredService<Hc900RealtimeService>());
builder.Services.AddHostedService<Hc900HistoryService>();
builder.Services.AddHostedService<Hc900DigitalEventDetectorService>();

// ── Application Services ──────────────────────────────────────────────────────
builder.Services.AddSingleton<IClock, SystemClock>();
builder.Services.AddSingleton<KstClock>();
builder.Services.AddSingleton<KoreanTimeRangeExtractor>();

builder.Services.AddSingleton<SqlValidatorOptions>(_ => new SqlValidatorOptions
{
    RequiredTables   = ["history_table"],
    AllowedTables    = ["history_table", "hc900_map_master", "realtime_table", "tag_metadata", "v_tag_summary"],
    MaxSubqueryDepth = 4
});
builder.Services.AddSingleton<SqlValidator>();
builder.Services.AddScoped<ITextToSqlService, TextToSqlService>();

// ── P&ID Services ─────────────────────────────────────────────────────────────
builder.Services.AddScoped<IPidExtractorService, PidExtractorService>();
builder.Services.AddScoped<ITagMappingService, TagMappingService>();
builder.Services.AddScoped<IPidGraphService, PidGraphService>();
builder.Services.AddScoped<IStatusStore, DbStatusStore>();
builder.Services.AddSingleton<IPidGraphEventBroadcaster, PidGraphEventBroadcaster>();

// ── Feedforward Advisory Engine ───────────────────────────────────────────────
builder.Services.AddSingleton<Hc900Crawler.Infrastructure.Control.FeedforwardEngine>();
builder.Services.AddSingleton<Hc900Crawler.Core.Application.Feedforward.IFeedforwardAdvisoryStore,
    Hc900Crawler.Infrastructure.Control.FeedforwardAdvisoryStore>();
builder.Services.AddScoped<Hc900Crawler.Core.Application.Feedforward.IFeedforwardConfigStore,
    Hc900Crawler.Infrastructure.Control.FeedforwardConfigStore>();
builder.Services.AddScoped<Hc900Crawler.Core.Application.Feedforward.IFeedforwardAuditService,
    Hc900Crawler.Infrastructure.Control.FeedforwardAuditService>();
builder.Services.AddSingleton<Hc900Crawler.Core.Application.Feedforward.IFeedforwardWriteGuard,
    Hc900Crawler.Infrastructure.Control.FeedforwardWriteGuard>();
builder.Services.AddSingleton<Hc900Crawler.Infrastructure.Control.FeedforwardSupervisor>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<Hc900Crawler.Infrastructure.Control.FeedforwardSupervisor>());
builder.Services.AddSingleton<Hc900Crawler.Core.Application.Feedforward.ISimOverrideStore,
    Hc900Crawler.Infrastructure.Control.SimOverrideStore>();
builder.Services.AddSingleton<Hc900Crawler.Core.Application.Feedforward.ICompositionStore,
    Hc900Crawler.Infrastructure.Control.CompositionStore>();
builder.Services.AddScoped<Hc900Crawler.Infrastructure.Control.FeedRampAdvisorService>();

// ── MCP Service ───────────────────────────────────────────────────────────────
builder.Services.AddHttpClient(McpClient.HttpClientName, c =>
{
    c.BaseAddress = new Uri("http://localhost:5001");
    c.Timeout = TimeSpan.FromSeconds(McpClient.ExtendedTimeoutSeconds + 60);
}).SetHandlerLifetime(TimeSpan.FromMinutes(5));
builder.Services.AddSingleton<McpClient>();
builder.Services.AddSingleton<IMcpService, McpService>();
builder.Services.AddHostedService<McpServerHostedService>();

// ── Knowledge Base (RAG) ──────────────────────────────────────────────────────
builder.Services.AddHttpClient("KbQdrant", (sp, c) =>
{
    var cfg = sp.GetRequiredService<IConfiguration>();
    c.BaseAddress = new Uri(cfg["Kb:QdrantUrl"] ?? "http://localhost:6333");
    c.Timeout = TimeSpan.FromSeconds(30);
});
builder.Services.AddSingleton<KbQdrantClient>();
builder.Services.AddSingleton<KbStorageService>();
builder.Services.AddSingleton<KbEmbeddingClient>();
builder.Services.AddScoped<IKbAuthService, KbAuthService>();
builder.Services.AddSingleton<Hc900Crawler.Infrastructure.Docs.DocBrowserService>();
builder.Services.AddHostedService<KbStartupService>();
builder.Services.AddHostedService<KbIngestWorker>();

// ── Ollama / vLLM HttpClients ─────────────────────────────────────────────────
builder.Services.AddHttpClient("Ollama", c =>
{
    c.BaseAddress = new Uri("http://localhost:11434");
    c.Timeout = TimeSpan.FromSeconds(1800);
}).SetHandlerLifetime(Timeout.InfiniteTimeSpan);

builder.Services.AddHttpClient("Vllm", c =>
{
    c.BaseAddress = new Uri("http://localhost:8000");
    c.Timeout = TimeSpan.FromSeconds(1800);
}).SetHandlerLifetime(Timeout.InfiniteTimeSpan);

// ── CORS ──────────────────────────────────────────────────────────────────────
builder.Services.AddCors(opt =>
    opt.AddDefaultPolicy(p =>
    {
        var origins = builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>();
        if (origins == null || origins.Length == 0 || (origins.Length == 1 && origins[0] == "*"))
            p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
        else
            p.WithOrigins(origins).AllowAnyMethod().AllowAnyHeader();
    }));

builder.WebHost.UseUrls("http://0.0.0.0:5000");

var app = builder.Build();

// ── DB 초기화 ─────────────────────────────────────────────────────────────────
try
{
    using var scope = app.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<IExperionDbService>();
    await db.InitializeAsync();

    try
    {
        var kbAuth = scope.ServiceProvider.GetRequiredService<IKbAuthService>();
        await kbAuth.EnsureCredentialAsync();
    }
    catch (Exception kbEx)
    {
        var lg = app.Services.GetRequiredService<ILogger<Program>>();
        lg.LogWarning(kbEx, "[Kb] 관리자 비밀번호 초기화 실패");
    }
}
catch (Exception ex)
{
    var logger = app.Services.GetRequiredService<ILogger<Program>>();
    logger.LogWarning(ex, "[DB] 초기화 실패 — DB 관련 기능 비활성화");
}

// ── Middleware ────────────────────────────────────────────────────────────────
app.UseCors();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseDefaultFiles();
app.UseStaticFiles();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();
