using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Mvc;
using ZhonTai.Admin.Core.Dto;
using ZhonTai.Admin.Services;
using NPP.SmartSchedue.Api.Contracts.Services.Work;
using NPP.SmartSchedue.Api.Contracts.Services.Work.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Work.Output;
using NPP.SmartSchedue.Api.Repositories.Work;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;

namespace NPP.SmartSchedue.Api.Services.Work;

/// <summary>
/// 工序服务
/// </summary>
[DynamicApi(Area = "app")]
public class ProcessService : BaseService, IProcessService, IDynamicApi
{
    private readonly ProcessRepository _processRepository;
    private readonly ProcessGroupRelationRepository _processGroupRelationRepository;
    
    /// <summary>
    /// 【线程安全修复】静态锁对象，用于避免 FreeSql RepositoryDbContext 并发键冲突
    /// </summary>
    private static readonly SemaphoreSlim _dbAccessSemaphore = new(5, 5); // 允许最多5个并发数据库访问

    public ProcessService(ProcessRepository processRepository, ProcessGroupRelationRepository processGroupRelationRepository)
    {
        _processRepository = processRepository;
        _processGroupRelationRepository = processGroupRelationRepository;
    }

    /// <summary>
    /// 查询
    /// 【线程安全修复】使用信号量控制并发访问，避免 FreeSql RepositoryDbContext 键冲突
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<ProcessGetOutput> GetAsync(long id)
    {
        await _dbAccessSemaphore.WaitAsync();
        try
        {
            var output = await _processRepository.Select
                .WhereDynamic(id)
                .ToOneAsync<ProcessGetOutput>();

            return output;
        }
        finally
        {
            _dbAccessSemaphore.Release();
        }
    }

    /// <summary>
    /// 查询分页
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<PageOutput<ProcessGetPageOutput>> GetPageAsync(PageInput<ProcessGetPageInput> input)
    {
        var list = await _processRepository.Select
            .WhereIf(!string.IsNullOrEmpty(input.Filter?.ProcessCode), a => a.ProcessCode.Contains(input.Filter.ProcessCode))
            .WhereIf(!string.IsNullOrEmpty(input.Filter?.ProcessName), a => a.ProcessName.Contains(input.Filter.ProcessName))
            .WhereIf(!string.IsNullOrEmpty(input.Filter?.ProcessCategory), a => a.ProcessCategory.Contains(input.Filter.ProcessCategory))
            .WhereIf(input.Filter?.IsEnabled.HasValue == true, a => a.IsEnabled == input.Filter.IsEnabled.Value)
            .Count(out var total)
            .OrderByDescending(a => a.Id)
            .Page(input.CurrentPage, input.PageSize)
            .ToListAsync<ProcessGetPageOutput>();

        var data = new PageOutput<ProcessGetPageOutput>()
        {
            List = list,
            Total = total
        };

        return data;
    }

    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<long> AddAsync(ProcessAddInput input)
    {
        var entity = Mapper.Map<ProcessEntity>(input);
        var result = await _processRepository.InsertAsync(entity);
        return result.Id;
    }

    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task UpdateAsync(ProcessUpdateInput input)
    {
        var entity = await _processRepository.GetAsync(input.Id);
        Mapper.Map(input, entity);
        await _processRepository.UpdateAsync(entity);
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task DeleteAsync(long id)
    {
        await _processRepository.DeleteAsync(id);
    }

    /// <summary>
    /// 软删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task SoftDeleteAsync(long id)
    {
        await _processRepository.SoftDeleteAsync(id);
    }

    /// <summary>
    /// 批量软删除
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public async Task BatchSoftDeleteAsync(long[] ids)
    {
        await _processRepository.SoftDeleteAsync(ids);
    }

    /// <summary>
    /// 启用工序
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task EnableAsync(long id)
    {
        var entity = await _processRepository.GetAsync(id);
        if (entity != null)
        {
            entity.IsEnabled = true;
            await _processRepository.UpdateAsync(entity);
        }
    }

    /// <summary>
    /// 禁用工序
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task DisableAsync(long id)
    {
        var entity = await _processRepository.GetAsync(id);
        if (entity != null)
        {
            entity.IsEnabled = false;
            await _processRepository.UpdateAsync(entity);
        }
    }

    /// <summary>
    /// 根据工序组ID获取工序列表
    /// </summary>
    /// <param name="processGroupId">工序组ID</param>
    /// <returns>工序列表</returns>
    public async Task<List<ProcessInfo>> GetProcessesByGroupIdAsync(long processGroupId)
    {
        var relations = await _processGroupRelationRepository.Select
            .Where(a => a.ProcessGroupId == processGroupId && a.IsEnabled)
            .OrderBy(a => a.RelationOrder)
            .ToListAsync();

        var processIds = relations.Select(r => r.ProcessId).ToArray();
        var processes = await _processRepository.Select
            .Where(a => processIds.Contains(a.Id))
            .ToListAsync();

        var result = new List<ProcessInfo>();
        foreach (var relation in relations)
        {
            var process = processes.FirstOrDefault(p => p.Id == relation.ProcessId);
            if (process != null)
            {
                result.Add(new ProcessInfo
                {
                    ProcessGroupId = relation.ProcessGroupId,
                    ProcessId = relation.ProcessId,
                    ProcessCode = process.ProcessCode,
                    ProcessName = process.ProcessName,
                    ProcessCategory = process.ProcessCategory,
                    EquipmentType = process.EquipmentType,
                    TheoreticalDuration = process.TheoreticalDuration,
                    RelationOrder = relation.RelationOrder,
                    RelationType = relation.RelationType,
                    PredecessorProcessId = relation.PredecessorProcessId,
                    SuccessorProcessId = relation.SuccessorProcessId,
                });
            }
        }

        return result;
    }
} 