using System;
using Lada.Framework.Data.Domains.Finance;
using Lada.Framework.Data.Domains.Identity;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Helpers;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Finances;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finances;
using Ladaer.BackEnd.Infrastructures.DTO;
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using System.IO;

namespace Ladaer.BackEnd.Infrastructures.Services.Finances
{
    /// <summary>
    /// Interface cho service quản lý tài khoản ngân hàng
    /// </summary>
    public interface IBankAccountService
    {
        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng
        /// </summary>
        Task<SmartTableResult<BankAccountItem>> Search(SmartTableParam param);

        /// <summary>
        /// Lấy chi tiết tài khoản ngân hàng
        /// </summary>
        Task<BankAccountDetailModel> GetById(int id);

        /// <summary>
        /// Tạo hoặc cập nhật tài khoản ngân hàng
        /// </summary>
        Task<BaseResult> CreateOrUpdate(BankAccountModel model);

        /// <summary>
        /// Xóa tài khoản ngân hàng
        /// </summary>
        Task<BaseResult> Delete(int id);

        /// <summary>
        /// Tìm kiếm giao dịch ngân hàng
        /// </summary>
        Task<SmartTableResult<BankTransactionItem>> SearchTransactions(SmartTableParam param);

        /// <summary>
        /// Import sao kê ngân hàng
        /// </summary>
        Task<BankStatementImportResult> ImportBankStatement(BankStatementImportModel model, int userId, string userName);

        /// <summary>
        /// Lấy danh sách tài khoản ngân hàng đang hoạt động
        /// </summary>
        Task<List<BankAccountItem>> GetActiveAccounts();

        /// <summary>
        /// Tìm kiếm lịch sử import
        /// </summary>
        Task<SmartTableResult<BankStatementImportItem>> SearchImportHistory(SmartTableParam param);

        /// <summary>
        /// Cập nhật số dư tài khoản
        /// </summary>
        Task<BaseResult> UpdateBalance(int accountId, decimal newBalance);

        /// <summary>
        /// Cập nhật số dư tài khoản với thông tin user
        /// </summary>
        Task<BaseResult> UpdateBalance(int accountId, decimal newBalance, int updatedBy, string updatedByUserName);

    }

    /// <summary>
    /// Service quản lý tài khoản ngân hàng
    /// </summary>
    public class BankAccountService : IBankAccountService
    {
        private readonly IRepository<Bank> _bankRepository;
        private readonly IRepository<BankAccount> _bankAccountRepository;
        private readonly IRepository<BankTransaction> _bankTransactionRepository;
        private readonly IRepository<BankStatementImport> _importRepository;
        private readonly IUserRepository<User> _userRepository;
        private readonly IBankStatementParser _statementParser;
        private readonly IExcelFileService _excelFileService;

        public BankAccountService(
            IRepository<Bank> bankRepository,
            IRepository<BankAccount> bankAccountRepository,
            IRepository<BankTransaction> bankTransactionRepository,
            IRepository<BankStatementImport> importRepository,
            IUserRepository<User> userRepository,
            IBankStatementParser statementParser,
            IExcelFileService excelFileService)
        {
            _bankRepository = bankRepository;
            _bankAccountRepository = bankAccountRepository;
            _bankTransactionRepository = bankTransactionRepository;
            _importRepository = importRepository;
            _userRepository = userRepository;
            _statementParser = statementParser;
            _excelFileService = excelFileService;
        }

        public async Task<SmartTableResult<BankAccountItem>> Search(SmartTableParam param)
        {
            IQueryable<BankAccount> query = _bankAccountRepository.Query()
                .Include(x => x.Bank)
                .Include(x => x.ManagerUser);

            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword.ToString().Trim().ToLower();
                    query = query.Where(x => x.AccountName.ToLower().Contains(keyword) ||
                                            x.AccountNumber.Contains(keyword) ||
                                            x.Bank.FullName.ToLower().Contains(keyword));
                }



                if (search.ManagerUserId != null)
                {
                    int managerUserId = search.ManagerUserId;
                    query = query.Where(x => x.ManagerUserId == managerUserId);
                }

                if (search.CreatedFrom != null && search.CreatedTo != null)
                {
                    DateTimeOffset createdFrom = search.CreatedFrom;
                    DateTimeOffset createdTo = search.CreatedTo;
                    query = query.Where(x => x.CreatedTime >= createdFrom && x.CreatedTime <= createdTo);
                }
            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = true };
            return await query.ToSmartTableResultAsync(param, x => x.ToItem());
        }

        public async Task<BankAccountDetailModel> GetById(int id)
        {
            var account = await _bankAccountRepository.Query()
                .Include(x => x.ManagerUser)
                .FirstOrDefaultAsync(x => x.Id == id);

            if (account == null)
                throw new ArgumentException("Không tìm thấy tài khoản ngân hàng");

            var transactionCount = await _bankTransactionRepository.Query()
                .CountAsync(x => x.BankAccountId == id);

            var lastTransaction = await _bankTransactionRepository.Query()
                .Where(x => x.BankAccountId == id)
                .OrderByDescending(x => x.TransactionDate)
                .FirstOrDefaultAsync();

            // Tính toán số liệu tháng hiện tại
            var currentMonth = DateTimeOffset.Now.StartOfMonth();
            var nextMonth = currentMonth.AddMonths(1);

            var monthlyTransactions = await _bankTransactionRepository.Query()
                .Where(x => x.BankAccountId == id &&
                           x.TransactionDate >= currentMonth &&
                           x.TransactionDate < nextMonth)
                .ToListAsync();

            var monthlyIncome = monthlyTransactions.Sum(x => x.CreditAmount);
            var monthlyOutcome = monthlyTransactions.Sum(x => x.DebitAmount);

            return new BankAccountDetailModel
            {
                Id = account.Id,
                AccountName = account.AccountName,
                AccountNumber = account.AccountNumber,
                ManagerUserId = account.ManagerUserId,
                ManagerUserName = account.ManagerUser?.UserName ?? "",
                ManagerFullName = account.ManagerUser?.FullName ?? "",
                LastBalanceUpdate = account.LastBalanceUpdate,
                LastTransactionDate = lastTransaction?.TransactionDate,
                TransactionCount = transactionCount,
                MonthlyIncome = monthlyIncome,
                MonthlyOutcome = monthlyOutcome,
                CreatedTime = account.CreatedTime,
                UpdatedTime = account.UpdatedTime
            };
        }

        public async Task<BaseResult> CreateOrUpdate(BankAccountModel model)
        {
            var result = new BaseResult();

            try
            {
                // Kiểm tra trùng lặp số tài khoản
                var existingAccount = await _bankAccountRepository.Query()
                    .FirstOrDefaultAsync(x => x.BankId == model.BankId &&
                                             x.AccountNumber == model.AccountNumber &&
                                             x.Id != model.Id);

                if (existingAccount != null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Số tài khoản đã tồn tại trong hệ thống";
                    return result;
                }

                if (model.Id > 0)
                {
                    // Update
                    var account = await _bankAccountRepository.GetByIdAsync(model.Id);
                    if (account == null)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Không tìm thấy tài khoản ngân hàng";
                        return result;
                    }

                    account.AccountName = model.AccountName;
                    account.AccountNumber = model.AccountNumber;
                    account.BankId = model.BankId;
                    account.ManagerUserId = model.ManagerUserId;
                    account.UpdatedTime = DateTimeOffset.Now;
                    account.UpdatedBy = model.UpdatedBy;
                    account.UpdatedByUserName = model.UpdatedByUserName;

                    await _bankAccountRepository.UpdateAsync(account);
                    result.Message = "Cập nhật tài khoản ngân hàng thành công";
                }
                else
                {
                    // Create
                    var account = new BankAccount
                    {
                        AccountName = model.AccountName,
                        AccountNumber = model.AccountNumber,
                        BankId = model.BankId,
                        ManagerUserId = model.ManagerUserId,
                        CreatedTime = DateTimeOffset.Now,
                        UpdatedTime = DateTimeOffset.Now,
                        CreatedBy = model.UpdatedBy,
                        CreatedByUserName = model.UpdatedByUserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName
                    };

                    await _bankAccountRepository.InsertAsync(account);
                    result.Message = "Tạo tài khoản ngân hàng thành công";
                }
                result.Result = Result.Success;
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        public async Task<BaseResult> Delete(int id)
        {
            var result = new BaseResult();

            try
            {
                var account = await _bankAccountRepository.GetByIdAsync(id);
                if (account == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tài khoản ngân hàng";
                    return result;
                }

                // Kiểm tra có giao dịch không
                var hasTransactions = await _bankTransactionRepository.Query()
                    .AnyAsync(x => x.BankAccountId == id);

                if (hasTransactions)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không thể xóa tài khoản đã có giao dịch";
                    return result;
                }

                await _bankAccountRepository.DeleteAsync(account);

                result.Result = Result.Success;
                result.Message = "Xóa tài khoản ngân hàng thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        public async Task<SmartTableResult<BankTransactionItem>> SearchTransactions(SmartTableParam param)
        {
            IQueryable<BankTransaction> query = _bankTransactionRepository.Query()
                .Include(x => x.BankAccount);

            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword.ToString().Trim().ToLower();
                    query = query.Where(x => x.Description.ToLower().Contains(keyword) ||
                                            x.TransactionCode.ToLower().Contains(keyword) ||
                                            x.CounterpartyName.ToLower().Contains(keyword));
                }

                if (search.BankAccountId != null)
                {
                    int bankAccountId = search.BankAccountId;
                    query = query.Where(x => x.BankAccountId == bankAccountId);
                }

                if (search.TransactionDateFrom != null && search.TransactionDateTo != null)
                {


                    DateTimeOffset start = search.TransactionDateFrom;
                    DateTimeOffset end = search.TransactionDateTo;
                    DateTimeOffset startParam = start.StartOfDay();
                    DateTimeOffset endParam = end.EndOfDay();


                    query = query.Where(x => x.TransactionDate >= startParam && x.TransactionDate <= endParam);
                }

                if (search.AmountFrom != null && search.AmountTo != null)
                {
                    decimal amountFrom = search.AmountFrom;
                    decimal amountTo = search.AmountTo;
                    query = query.Where(x => (x.CreditAmount >= amountFrom && x.CreditAmount <= amountTo) ||
                                            (x.DebitAmount >= amountFrom && x.DebitAmount <= amountTo));
                }

                if (search.TransactionDirection != null)
                {
                    string direction = search.TransactionDirection.ToString();
                    if (direction.ToLower() == "credit")
                        query = query.Where(x => x.CreditAmount > 0);
                    else if (direction.ToLower() == "debit")
                        query = query.Where(x => x.DebitAmount > 0);
                }

                if (search.ProcessStatus != null)
                {
                    // Xử lý an toàn khi parse enum từ dynamic object
                    if (Enum.TryParse<TransactionProcessStatus>(search.ProcessStatus.ToString(), out TransactionProcessStatus status))
                    {
                        query = query.Where(x => x.ProcessStatus == status);
                    }
                }

                if (search.TransactionType != null)
                {
                    // Xử lý an toàn khi parse enum từ dynamic object
                    if (Enum.TryParse<BankTransactionType>(search.TransactionType.ToString(), out BankTransactionType transactionType))
                    {
                        query = query.Where(x => x.TransactionType == transactionType);
                    }
                }

                if (search.ImportId != null)
                {
                    Guid importId = search.ImportId;
                    query = query.Where(x => x.ImportId == importId);
                }
            }
            param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };
            return await query.ToSmartTableResultAsync(param, x => x.ToItem());
        }

        public async Task<BankStatementImportResult> ImportBankStatement(BankStatementImportModel model, int userId, string userName)
        {
            var result = new BankStatementImportResult();
            var stopwatch = Stopwatch.StartNew();

            try
            {
                // Validate file
                if (model.ExcelFile == null || model.ExcelFile.Length == 0)
                {
                    result.Result = Result.Failed;
                    result.Message = "File không hợp lệ";
                    return result;
                }

                // Validate account exists
                var account = await _bankAccountRepository.GetByIdAsync(model.BankAccountId);
                if (account == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tài khoản ngân hàng";
                    return result;
                }

                var bank = await _bankRepository.Query().FirstOrDefaultAsync(b => b.Id == account.BankId);
                if (bank == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy ngân hàng";
                    return result;
                }


                // Save Excel file using ExcelFileService
                var fileBytes = await GetFileBytesAsync(model.ExcelFile);
                var fileName = Path.GetFileNameWithoutExtension(model.ExcelFile.FileName);
                var fileSaveResult = await _excelFileService.SaveExcelFileAsync(fileBytes, fileName, "bank-statements");

                if (fileSaveResult.Result != Result.Success)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Lỗi lưu file: {fileSaveResult.Message}";
                    return result;
                }

                // Create import record
                var importRecord = new BankStatementImport
                {
                    Id = Guid.NewGuid(),
                    BankAccountId = model.BankAccountId,
                    OriginalFileName = model.ExcelFile.FileName,
                    FilePath = fileSaveResult.FilePath,
                    FileSize = model.ExcelFile.Length,
                    BankCode = bank.BankCode,
                    OverwriteExisting = model.OverwriteExisting,
                    DataFromDate = model.FromDate,
                    DataToDate = model.ToDate,
                    ImportStatus = ImportStatus.Processing,
                    ProcessStartTime = DateTimeOffset.Now,
                    ImportedByUserId = userId,
                    ImportedByUserName = userName,
                    CreatedTime = DateTimeOffset.Now,
                    UpdatedTime = DateTimeOffset.Now,
                    CreatedBy = userId,
                    CreatedByUserName = userName,
                    UpdatedBy = userId,
                    UpdatedByUserName = userName
                };

                await _importRepository.InsertAsync(importRecord);

                // Parse Excel file
                var parseResult = await _statementParser.ParseBankStatement(model, bank.BankCode, userId, userName);

                stopwatch.Stop();

                // Update import record
                importRecord.TotalRows = parseResult.TotalRows;
                importRecord.ProcessedRows = parseResult.ProcessedRows;
                importRecord.ErrorRows = parseResult.ErrorRows;
                importRecord.ProcessEndTime = DateTimeOffset.Now;
                importRecord.ErrorDetails = string.Join("; ", parseResult.ErrorMessages);

                if (parseResult.IsSuccess)
                {
                    importRecord.ImportStatus = parseResult.ErrorRows > 0 ? ImportStatus.SuccessWithWarnings : ImportStatus.Success;

                    // Update import ID for transactions
                    foreach (var transaction in parseResult.Transactions)
                    {
                        transaction.ImportId = importRecord.Id;
                    }

                    // Update account balance if enabled
                    if (model.UpdateAccountBalance && parseResult.Transactions.Any())
                    {
                        var lastTransaction = parseResult.Transactions
                            .OrderByDescending(x => x.TransactionDate)
                            .ThenByDescending(x => x.DetailedTime ?? x.TransactionDate)
                            .FirstOrDefault();

                        if (lastTransaction != null)
                        {
                            account.LastBalanceUpdate = DateTimeOffset.Now;
                            account.LastTransactionDate = lastTransaction.TransactionDate;
                            await _bankAccountRepository.UpdateAsync(account);
                        }
                    }

                    result.ImportId = importRecord.Id;
                    result.TotalRows = parseResult.TotalRows;
                    result.ProcessedRows = parseResult.ProcessedRows;
                    result.ErrorRows = parseResult.ErrorRows;
                    result.ImportedTransactions = parseResult.Transactions.Select(x => x.ToItem()).ToList();
                    result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds;

                    if (parseResult.Transactions.Any())
                    {
                        result.FirstTransactionDate = parseResult.Transactions.Min(x => x.TransactionDate);
                        result.LastTransactionDate = parseResult.Transactions.Max(x => x.TransactionDate);
                    }

                    result.Result = Result.Success;
                    result.Message = $"Import thành công {parseResult.ProcessedRows}/{parseResult.TotalRows} giao dịch";

                    if (parseResult.ErrorRows > 0)
                    {
                        result.ErrorMessages = parseResult.ErrorMessages;
                        result.Message += $" (có {parseResult.ErrorRows} lỗi)";
                    }
                }
                else
                {
                    importRecord.ImportStatus = ImportStatus.Failed;
                    importRecord.ErrorMessage = parseResult.ErrorMessage;

                    result.Result = Result.Failed;
                    result.Message = parseResult.ErrorMessage;
                    result.ErrorMessages = parseResult.ErrorMessages;
                }

                await _importRepository.UpdateAsync(importRecord);
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        public async Task<List<BankAccountItem>> GetActiveAccounts()
        {
            var accounts = await _bankAccountRepository.Query()
                .Include(x => x.ManagerUser)
                .OrderBy(x => x.Bank.FullName)
                .ThenBy(x => x.AccountName)
                .ToListAsync();

            return accounts.Select(x => x.ToItem()).ToList();
        }

        public async Task<SmartTableResult<BankStatementImportItem>> SearchImportHistory(SmartTableParam param)
        {
            IQueryable<BankStatementImport> query = _importRepository.Query()
                .Include(x => x.BankAccount)
                .Include(x => x.ImportedByUser);

            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword.ToString().Trim().ToLower();
                    query = query.Where(x => x.OriginalFileName.ToLower().Contains(keyword) ||
                                            x.BankAccount.AccountName.ToLower().Contains(keyword) ||
                                            x.BankAccount.AccountNumber.Contains(keyword));
                }

                if (search.BankAccountId != null)
                {
                    int bankAccountId = search.BankAccountId;
                    query = query.Where(x => x.BankAccountId == bankAccountId);
                }


                if (search.ImportStatus != null)
                {
                    ImportStatus status = search.ImportStatus;
                    query = query.Where(x => x.ImportStatus == status);
                }

                if (search.ImportDateFrom != null && search.ImportDateTo != null)
                {
                    DateTimeOffset dateFrom = search.ImportDateFrom;
                    DateTimeOffset dateTo = search.ImportDateTo;
                    query = query.Where(x => x.CreatedTime >= dateFrom && x.CreatedTime <= dateTo);
                }

                if (search.ImportedByUserId != null)
                {
                    int userId = search.ImportedByUserId;
                    query = query.Where(x => x.ImportedByUserId == userId);
                }
            }

            return await query.ToSmartTableResultAsync(param, x => x.ToItem());
        }

        public async Task<BaseResult> UpdateBalance(int accountId, decimal newBalance)
        {
            var result = new BaseResult();

            try
            {
                var account = await _bankAccountRepository.GetByIdAsync(accountId);
                if (account == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tài khoản ngân hàng";
                    return result;
                }

                account.LastBalanceUpdate = DateTimeOffset.Now;
                account.UpdatedTime = DateTimeOffset.Now;
                // Note: UpdatedBy and UpdatedByUserName are not set in this method
                // Use the overload method UpdateBalance(accountId, newBalance, updatedBy, updatedByUserName) for full audit

                await _bankAccountRepository.UpdateAsync(account);

                result.Result = Result.Success;
                result.Message = "Cập nhật số dư thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        public async Task<BaseResult> UpdateBalance(int accountId, decimal newBalance, int updatedBy, string updatedByUserName)
        {
            var result = new BaseResult();

            try
            {
                var account = await _bankAccountRepository.GetByIdAsync(accountId);
                if (account == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tài khoản ngân hàng";
                    return result;
                }

                account.LastBalanceUpdate = DateTimeOffset.Now;
                account.UpdatedTime = DateTimeOffset.Now;
                account.UpdatedBy = updatedBy;
                account.UpdatedByUserName = updatedByUserName;

                await _bankAccountRepository.UpdateAsync(account);

                result.Result = Result.Success;
                result.Message = "Cập nhật số dư thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Helper method để convert IFormFile thành byte array
        /// </summary>
        private async Task<byte[]> GetFileBytesAsync(IFormFile file)
        {
            using var memoryStream = new MemoryStream();
            await file.CopyToAsync(memoryStream);
            return memoryStream.ToArray();
        }
    }
}
