using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OutputCaching;
using Microsoft.EntityFrameworkCore;
using Tiku.Api.Contracts;
using Tiku.Application.Catalog;
using Tiku.Application.Scoreline;
using Tiku.Application.Security;
using Tiku.Domain.Tenancy;
using Tiku.Infrastructure.Persistence;

namespace Tiku.Api.Controllers;

[ApiController]
[Tags("学生端-分数线")]
[AllowAnonymous]
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Scoreline)]
[Produces("application/json")]
[Route("api/scoreline")]
public sealed class ScorelineController(
    IScorelineQueryService scorelineQueryService,
    ITenantContext currentTenant,
    TikuDbContext dbContext) : ControllerBase
{
    private static readonly string[] DynamicPrefixes = ["field.", "min.", "max."];

    [HttpGet("fields")]
    [OutputCache(PolicyName = "TenantPublic")]
    [EndpointSummary("查询分数线字段配置")]
    [ProducesResponseType<CatalogList<ScorelineFieldItem>>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<CatalogList<ScorelineFieldItem>>> GetFields(
        [FromQuery] ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        return Ok(await scorelineQueryService.GetFieldsAsync(
            query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
            cancellationToken));
    }

    [HttpGet("records")]
    [EndpointSummary("分页查询分数线记录")]
    [ProducesResponseType<ScorelineRecordPage>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ScorelineRecordPage>> GetRecords(
        [FromQuery] ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        return Ok(await scorelineQueryService.GetRecordsAsync(
            query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken), ResolveDynamicFilters()),
            cancellationToken));
    }

    [HttpGet("records/cursor")]
    [EndpointSummary("游标分页查询分数线记录")]
    [ProducesResponseType<ScorelineRecordCursorPage>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<ScorelineRecordCursorPage>> GetRecordsCursor(
        [FromQuery] ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        return Ok(await scorelineQueryService.GetRecordsCursorAsync(
            query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken), ResolveDynamicFilters()),
            query.Cursor,
            cancellationToken));
    }

    [HttpGet("trend")]
    [EndpointSummary("查询历年分数线趋势")]
    [ProducesResponseType<CatalogList<ScorelineRecordItem>>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<CatalogList<ScorelineRecordItem>>> GetTrend(
        [FromQuery] ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        return Ok(await scorelineQueryService.GetTrendAsync(
            query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken), ResolveDynamicFilters()),
            cancellationToken));
    }

    [HttpGet("years")]
    [OutputCache(PolicyName = "TenantPublic")]
    [EndpointSummary("查询分数线可用年份")]
    [ProducesResponseType<CatalogList<int>>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<CatalogList<int>>> GetYears(
        [FromQuery] ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        return Ok(await scorelineQueryService.GetYearsAsync(
            query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
            cancellationToken));
    }

    private IReadOnlyCollection<ScorelineDynamicFilter> ResolveDynamicFilters()
    {
        var filters = new List<ScorelineDynamicFilter>();
        foreach (var (key, value) in Request.Query)
        {
            var prefix = DynamicPrefixes.FirstOrDefault(key.StartsWith);
            if (prefix is null)
            {
                continue;
            }

            var raw = value.FirstOrDefault();
            if (string.IsNullOrWhiteSpace(raw))
            {
                continue;
            }

            filters.Add(new ScorelineDynamicFilter(
                prefix.TrimEnd('.'),
                key[prefix.Length..],
                raw.Trim()));
        }

        return filters;
    }

    private async Task<Guid> ResolveTenantIdAsync(
        ScorelineQueryDto query,
        CancellationToken cancellationToken)
    {
        if (currentTenant.TenantId.HasValue)
        {
            return currentTenant.TenantId.Value;
        }

        var tenantCode = query.TenantCode ?? Request.Headers["x-tenant-code"].FirstOrDefault();
        if (string.IsNullOrWhiteSpace(tenantCode))
        {
            throw new TenantNotFoundException();
        }

        var tenantId = await dbContext.Tenants
            .Where(tenant =>
                tenant.Slug == tenantCode.Trim() &&
                tenant.Status == TenantStatus.Active)
            .Select(tenant => (Guid?)tenant.Id)
            .SingleOrDefaultAsync(cancellationToken);

        return tenantId ?? throw new TenantNotFoundException();
    }
}
