using CloudBuilder.AI.Data;
using CloudBuilder.AI.Entity;
using CloudBuilder.AI.Policy;
using CloudBuilder.AI.SearchCriteria;
using CloudBuilder.AI.Service.Utility;
using CloudBuilder.Core.DatabaseAccessor;
using CloudBuilder.Core.DatabaseAccessor.Entity;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Data;
using CloudBuilder.Security.Entity;
using CloudBuilder.Security.Policy;
using CloudBuilder.Security.Service;
using CloudBuilder.Security.Utility;
using DocumentFormat.OpenXml.ExtendedProperties;
using DocumentFormat.OpenXml.Presentation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics.Contracts;
using System.Text;
using System.Transactions;
namespace CloudBuilder.AI.Service
{
    public class AiBookService : IAiBookService
    {
        private readonly IApplicationService service;

        private IRepository<AiBookEntity> repository;

        private ChineseNameExtractor chineseNameExtractor;
        public AiBookService(IApplicationService service)
        {
            this.service = service;
            repository = service.GetRepository<IRepository<AiBookEntity>>();
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
        public AiBookData FindByKey(string key)
        {
            AiBookData data = new AiBookData();
            data.AiBook = repository.DetachedEntities.Where(x => x.Guid == key).FirstOrDefault()!;

            if (data.AiBook.FileId > 0)
            {
                IRepository<BookDmsFileViewEntity> repositoryUploadDmsFile = service.GetRepository<IRepository<BookDmsFileViewEntity>>();
                BookDmsFileViewEntity dms;

                dms = repositoryUploadDmsFile.DetachedEntities.Where(x => x.FileId == data.AiBook.FileId).FirstOrDefault()!;
                data.FileName = dms.OrgFileName;
            }

            return data;
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
        public AiBookEntity FindByTitle(string title)
        {
            return repository.DetachedEntities.Where(x => x.Title == title).FirstOrDefault()!;
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
        public AiBookResultData FindBySearchCriteria(AiBookSearchCriteria criteria)
        {
            AiBookResultData data = new AiBookResultData();
            AiBookEntity[] list = null;

            int count = 0;

            string sqlWhere = null;

            if (criteria.Filter != null && criteria.Filter.Length > 0)
            {
                sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter);
            }

            AiBookEntity entity = AiBookEntity.GetInstance();
            string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere);

            string err = null;
            try
            {
                list = repository.FromSql(sql).ToArray();
            }
            catch (System.Exception ex)
            {
                err = ex.Message;
            }


            if (list != null && list.Length > 0)
            {
                sql = entity.GetSelectCountFrom(sqlWhere);
                count = (int)repository.ExecuteScalar(sql);
            }

            data.Limit = criteria.limit;
            data.Page = criteria.page;
            data.Datas = list;
            data.Total = count;
            //data.Sql = sql;
            data.ErrorMessage = err;
            return data;
        }

        //[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Print)]
        public dynamic PrintBySearchCriteria(AiBookSearchCriteria criteria)
        {
            throw new NotImplementedException();
        }

        //[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Insert)]
        //[UnitOfWork]
        //public AiBookEntity Insert(AiBookEntity data)
        //{
        //    throw new NotImplementedException();
        //}

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Insert)]
        [UnitOfWork]
        public AiBookData Insert(AiBookData data)
        {
            AiBookEntity entity = repository.DetachedEntities.Where(x => x.Title == data.AiBook.Title).FirstOrDefault();
            if (entity != null)
            {
                throw new ValidatedException("记录已存在.");
            }

            ISecurityGeneratorNumberService securityGeneratorNumberService = service.ServiceProvider.GetService<ISecurityGeneratorNumberService>()!;

            data.AiBook.Guid = securityGeneratorNumberService.GetNo(AIPrefixPolicy.AI_BOOK, AIPrefixPolicy.GUID, AIPrefixPolicy.AI_BOOK_PREFIX, YesNoPolicy.NO, AIPrefixPolicy.AI_BOOK_GUID_FORMAT);

            repository.InsertNow(data.AiBook);

            IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
            if (data.AiChapters != null && data.AiChapters.Length > 0)
                repositoryAiChapterEntity.InsertNow(data.AiChapters);

            return data;
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
        [UnitOfWork]
        public AiBookData Update(AiBookData data)
        {
            AiBookEntity aiBook = repository.DetachedEntities.Where(x => x.Guid == data.AiBook.Guid).FirstOrDefault();
            if (aiBook == null)
            {
                throw new ValidatedException("记录不存在.");
            }

            ValidateHelper.Validate(service, data.AiBook, AiBookEntity.DB_NAME_AI_BOOK);

            ObjectCopyHelper.Copy(data.AiBook, aiBook);

            repository.UpdateNow(aiBook);

            return data;
        }


        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Delete)]
        [UnitOfWork]
        public void Delete(string key)
        {
            var ent = repository.DetachedEntities.Where(x => x.Guid == key).FirstOrDefault()!;
            if (ent != null) { repository.DeleteNow(ent); }
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Delete)]
        [UnitOfWork]
        public void Deletes(string[] keys)
        {
            foreach (string key in keys)
            {
                Delete(key);
            }
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
        [UnitOfWork]
        public AiBookData ProcessBook(string key, string encoding, string pattern)
        {
            AiBookData data = FindByKey(key);

            ChapterSplitter chapterSplitter = new ChapterSplitter();
            ParagraphSplitter paragraphSplitter = new ParagraphSplitter();

            IRepository<DmsFileEntity> repositoryDmsFile = repository.GetRepository<IRepository<DmsFileEntity>>();

            DmsFileEntity entity = repositoryDmsFile.DetachedEntities.Where(x => x.FileId == data.AiBook.FileId && x.CreatedBy == service.UserId).FirstOrDefault()!;

            if (entity == null) throw new ValidatedException("文件不存在.");

            var fileExtension = Path.GetExtension(entity.OrderKey);//获取文件格式，拓展名

            string file = FileTypePolicy.PackFilePath(service, entity.CreatedBy, entity.OrderKey);

            if (!File.Exists(file)) throw new ValidatedException("文件不存在.");

            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

            string context = File.ReadAllText(file, Encoding.GetEncoding(encoding));

            List<AiChapterEntity> aiChapterEntities = chapterSplitter.SplitNovelIntoChapters(context, pattern);

            if (aiChapterEntities == null || aiChapterEntities.Count() == 0) return data;

            aiChapterEntities.ToLookup(x => x.BookGuid = data.AiBook.Guid);
            aiChapterEntities.ToLookup(x => x.Status = ChapterStatusPolicy.PROCESS);

            data.AiChapters = aiChapterEntities.ToArray();

            paragraphSplitter.PackParagraphs(data);

            IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
            IRepository<AiParagraphEntity> repositoryAiParagraphEntity = repository.GetRepository<IRepository<AiParagraphEntity>>();

            IRepository<AiSentenceEntity> repositoryAiSentenceEntity = repository.GetRepository<IRepository<AiSentenceEntity>>();

            AiChapterEntity[] aiChapters = repositoryAiChapterEntity.DetachedEntities.Where(x => x.BookGuid == data.AiBook.Guid).ToArray();

            if (aiChapters != null && aiChapters.Length > 0)
            {
                foreach (AiChapterEntity aiChapter in aiChapters)
                {
                    AiParagraphEntity[] aiParagraphs = repositoryAiParagraphEntity.DetachedEntities.Where(x => x.ChapterGuid == aiChapter.Guid).ToArray();

                    if (aiParagraphs != null && aiParagraphs.Length > 0)
                    {
                        foreach (AiParagraphEntity aiParagraph in aiParagraphs)
                        {
                            AiSentenceEntity[] aiSentences = repositoryAiSentenceEntity.DetachedEntities.Where(x => x.ParagraphGuid == aiParagraph.Guid).ToArray();

                            if (aiSentences != null && aiSentences.Length > 0)
                            {
                                repositoryAiSentenceEntity.DeleteNow(aiSentences);
                            }
                        }

                        repositoryAiParagraphEntity.DeleteNow(aiParagraphs);
                    }


                }
                repositoryAiChapterEntity.DeleteNow(aiChapters);
            }

            repositoryAiChapterEntity.InsertNow(data.AiChapters);

            if (data.AiParagraphs == null || data.AiParagraphs.Count() == 0) return data;

            repositoryAiParagraphEntity.InsertNow(data.AiParagraphs);

            if (data.AiSentences == null || data.AiSentences.Count() == 0) return data;
            repositoryAiSentenceEntity.InsertNow(data.AiSentences);

            return FindByKey(key);
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
        [UnitOfWork]
        public void ExtractNames(string bookGuid)
        {
            ExtractNamesByChapterGuid(bookGuid, null);
        }

        [PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
        [UnitOfWork]
        public void ExtractNamesByChapterGuid(string bookGuid, string chapterGuid)
        {
            if (chineseNameExtractor == null) chineseNameExtractor = new ChineseNameExtractor(service);

            IRepository<AiChapterPersonEntity> repositoryAiChapterPersonEntity = repository.GetRepository<IRepository<AiChapterPersonEntity>>();

            IRepository<AiParagraphViewEntity> repositoryAiParagraphEntity = repository.GetRepository<IRepository<AiParagraphViewEntity>>();

            AiParagraphViewEntity[] paragraphs = repositoryAiParagraphEntity.DetachedEntities.Where(x => x.BookGuid == bookGuid && (string.IsNullOrEmpty(chapterGuid) || x.ChapterGuid == chapterGuid)).ToArray();

            if (paragraphs == null || paragraphs.Length == 0) return;

            List<string> names = new List<string>();
            List<AiChapterPersonEntity> aiChapterPersonEntities = new List<AiChapterPersonEntity>();
            AiChapterPersonEntity entity;
            int orderIndex = 0;
            foreach (var paragraph in paragraphs)
            {
                names = chineseNameExtractor.ExtractNames(paragraph.Content);

                if (names == null || names.Count() == 0) continue;

                orderIndex = 1;
                foreach (var name in names)
                {
                    entity = new AiChapterPersonEntity();
                    entity.Guid= Guid.NewGuid().ToString();
                    entity.ChapterGuid = paragraph.ChapterGuid;
                    entity.ParagraphGuid = paragraph.Guid;
                    entity.ParagraphIndex = paragraph.ParagraphIndex;
                    entity.OrderIndex = orderIndex++;
                    entity.PersonName = name;
                    aiChapterPersonEntities.Add(entity);
                }
            }

            if (aiChapterPersonEntities != null && aiChapterPersonEntities.Count() > 0)
                repositoryAiChapterPersonEntity.InsertNow(aiChapterPersonEntities);
        }
    }
}
