using CsvHelper;
using CsvHelper.Configuration;
using OfficeOpenXml;

namespace Service;

public interface IImportService
{
    /// <summary>
    /// 导入支付宝账单
    /// </summary>
    Task<(bool ok, string message)> ImportAlipayAsync(MemoryStream file, string fileExtension);

    /// <summary>
    /// 导入微信账单
    /// </summary>
    Task<(bool ok, string message)> ImportWeChatAsync(MemoryStream file, string fileExtension);
}

public class ImportService(
    ILogger<ImportService> logger,
    ITransactionRecordRepository transactionRecordRepository
) : IImportService
{
    public async Task<(bool ok, string message)> ImportAlipayAsync(MemoryStream file, string fileExtension)
    {
        var content = await ParseAsync(file, fileExtension);
        logger.LogInformation("转换后的支付宝账单数据行数: {RowCount}", content.Length);

        if (content.Length == 0)
        {
            logger.LogWarning("支付宝账单文件解析后无数据行");
            return (false, "支付宝账单文件解析后无数据行");
        }

        var addTransactionRecords = new List<TransactionRecord>();
        var updateTransactionRecords = new List<TransactionRecord>();
        foreach (var row in content)
        {
            var importNo = row.ContainsKey("交易号") ? row["交易号"] : string.Empty;

            if (string.IsNullOrWhiteSpace(importNo))
            {
                logger.LogWarning("跳过无交易号的记录: {Row}", row);
                continue;
            }

            var existingRecord = await transactionRecordRepository.ExistsByImportNoAsync(importNo, "支付宝");

            if (existingRecord != null)
            {
                existingRecord.Reason = GetReason(row);
                existingRecord.Amount = GetDecimalValue(row, "金额（元）");
                existingRecord.RefundAmount = GetDecimalValue(row, "成功退款（元）");
                existingRecord.OccurredAt = GetDateTimeValue(row, "交易创建时间");
                existingRecord.Type = GetTransactionType(row, "收/支");
                updateTransactionRecords.Add(existingRecord);
                continue;
            }

            var transactionRecord = new TransactionRecord
            {
                Reason = GetReason(row),
                Amount = GetDecimalValue(row, "金额（元）"),
                RefundAmount = GetDecimalValue(row, "成功退款（元）"),
                Balance = 0,
                OccurredAt = GetDateTimeValue(row, "交易创建时间"),
                Type = GetTransactionType(row, "收/支"),
                ImportNo = importNo,
                ImportFrom = "支付宝"
            };

            addTransactionRecords.Add(transactionRecord);
        }

        if (addTransactionRecords.Count == 0 && updateTransactionRecords.Count == 0)
        {
            logger.LogWarning("未找到可导入或更新的支付宝交易记录");
            return (false, "未找到可导入或更新的支付宝交易记录");
        }

        var message = new StringBuilder();
        if (addTransactionRecords.Count > 0)
        {
            if (await transactionRecordRepository.AddRangeAsync(addTransactionRecords))
            {
                logger.LogInformation("成功导入支付宝交易记录数: {Count}", addTransactionRecords.Count);
                message.AppendLine($"成功导入支付宝交易记录数: {addTransactionRecords.Count}");
            }
        }

        if (updateTransactionRecords.Count > 0)
        {
            if (await transactionRecordRepository.UpdateRangeAsync(updateTransactionRecords))
            {
                logger.LogInformation("成功更新支付宝交易记录数: {Count}", updateTransactionRecords.Count);
                message.AppendLine($"成功更新支付宝交易记录数: {updateTransactionRecords.Count}");
            }
        }

        return (true, message.ToString());

        string GetReason(IDictionary<string, string> row)
        {
            var reason = string.Empty;
            if (row.ContainsKey("交易对方") && !string.IsNullOrWhiteSpace(row["交易对方"]))
            {
                reason += row["交易对方"];
            }

            if (row.ContainsKey("商品名称") && !string.IsNullOrWhiteSpace(row["商品名称"]))
            {
                reason += row["商品名称"];
            }

            return reason;
        }

        decimal GetDecimalValue(IDictionary<string, string> row, string key)
        {
            if (row.ContainsKey(key) && decimal.TryParse(row[key], out var value))
            {
                return value;
            }

            return 0m;
        }

        DateTime GetDateTimeValue(IDictionary<string, string> row, string key)
        {
            if (!row.ContainsKey(key))
            {
                return DateTime.MinValue;
            }

            foreach (var format in DateTimeFormats)
            {
                if (DateTime.TryParseExact(
                    row[key],
                    format,
                    CultureInfo.InvariantCulture,
                    DateTimeStyles.None,
                    out var value))
                {
                    return value;
                }
            }

            if (DateTime.TryParse(row[key], out var value2))
            {
                return value2;
            }

            return DateTime.MinValue;
        }

        TransactionType GetTransactionType(IDictionary<string, string> row, string key)
        {
            if (!row.ContainsKey(key))
            {
                return TransactionType.None;
            }

            var typeStr = row[key];

            return typeStr switch
            {
                "支出" => TransactionType.Expense,
                "收入" => TransactionType.Income,
                _ => TransactionType.None
            };
        }
    }

    public async Task<(bool ok, string message)> ImportWeChatAsync(MemoryStream file, string fileExtension)
    {
        var content = await ParseAsync(file, fileExtension);
        logger.LogInformation("转换后的微信账单数据行数: {RowCount}", content.Length);

        if (content.Length == 0)
        {
            logger.LogWarning("微信账单文件解析后无数据行");
            return (false, "微信账单文件解析后无数据行");
        }

        var addTransactionRecords = new List<TransactionRecord>();
        var updateTransactionRecords = new List<TransactionRecord>();
        foreach (var row in content)
        {
            var importNo = row.ContainsKey("交易单号") ? row["交易单号"] : string.Empty;

            if (string.IsNullOrWhiteSpace(importNo))
            {
                logger.LogWarning("跳过无交易单号的记录: {Row}", row);
                continue;
            }

            var existingRecord = await transactionRecordRepository.ExistsByImportNoAsync(importNo, "微信");

            if (existingRecord != null)
            {
                existingRecord.Reason = GetReason(row);
                existingRecord.Amount = GetAmountValue(row, "金额(元)");
                existingRecord.OccurredAt = GetDateTimeValue(row, "交易时间");
                existingRecord.Type = GetTransactionType(row, "收/支");
                existingRecord.RefundAmount = GetRefundAmountValue(row);
                updateTransactionRecords.Add(existingRecord);
                continue;
            }

            var transactionRecord = new TransactionRecord
            {
                Reason = GetReason(row),
                Amount = GetAmountValue(row, "金额(元)"),
                RefundAmount = GetRefundAmountValue(row),
                Balance = 0,
                OccurredAt = GetDateTimeValue(row, "交易时间"),
                Type = GetTransactionType(row, "收/支"),
                ImportNo = importNo,
                ImportFrom = "微信"
            };

            addTransactionRecords.Add(transactionRecord);
        }

        if (addTransactionRecords.Count == 0 && updateTransactionRecords.Count == 0)
        {
            logger.LogWarning("未找到可导入或更新的微信交易记录");
            return (false, "未找到可导入或更新的微信交易记录");
        }

        var message = new StringBuilder();
        if (addTransactionRecords.Count > 0)
        {
            if (await transactionRecordRepository.AddRangeAsync(addTransactionRecords))
            {
                logger.LogInformation("成功导入微信交易记录数: {Count}", addTransactionRecords.Count);
                message.AppendLine($"成功导入微信交易记录数: {addTransactionRecords.Count}");
            }
        }

        if (updateTransactionRecords.Count > 0)
        {
            if (await transactionRecordRepository.UpdateRangeAsync(updateTransactionRecords))
            {
                logger.LogInformation("成功更新微信交易记录数: {Count}", updateTransactionRecords.Count);
                message.AppendLine($"成功更新微信交易记录数: {updateTransactionRecords.Count}");
            }
        }

        return (true, message.ToString());

        string GetReason(IDictionary<string, string> row)
        {
            var reason = string.Empty;
            if (row.ContainsKey("交易类型") && !string.IsNullOrWhiteSpace(row["交易类型"]))
            {
                reason += row["交易类型"];
            }

            if (row.ContainsKey("交易对方") && !string.IsNullOrWhiteSpace(row["交易对方"]))
            {
                reason += row["交易对方"];
            }

            if (row.ContainsKey("商品") && !string.IsNullOrWhiteSpace(row["商品"]))
            {
                reason += row["商品"];
            }

            return reason;
        }

        decimal GetAmountValue(IDictionary<string, string> row, string key)
        {
            if (row.ContainsKey(key) && decimal.TryParse(row[key].TrimStart('¥').TrimStart('￥'), out var value))
            {
                return value;
            }

            return 0m;
        }

        DateTime GetDateTimeValue(IDictionary<string, string> row, string key)
        {
            if(!row.ContainsKey(key))
            {
                return DateTime.MinValue;
            }

            foreach (var format in DateTimeFormats)
            {
                if (DateTime.TryParseExact(
                    row[key],
                    format,
                    CultureInfo.InvariantCulture,
                    DateTimeStyles.None,
                    out var value))
                {
                    return value;
                }
            }

            if (DateTime.TryParse(row[key], out var value2))
            {
                return value2;
            }

            return DateTime.MinValue;
        }

        TransactionType GetTransactionType(IDictionary<string, string> row, string key)
        {
            if (!row.ContainsKey(key))
            {
                return TransactionType.None;
            }

            var typeStr = row[key];

            return typeStr switch
            {
                "支出" => TransactionType.Expense,
                "收入" => TransactionType.Income,
                _ => TransactionType.None
            };
        }

        decimal GetRefundAmountValue(IDictionary<string, string> row)
        {
            if (!row.ContainsKey("当前状态"))
            {
                return 0m;
            }

            var status = row["当前状态"];

            if (!status.Contains("退款"))
            {
                return 0m;
            }

            // 使用正则表达式提取退款金额
            var regex = new Regex(@"￥(-?\d+(\.\d+)?)");
            var match = regex.Match(status);
            if (match.Success && decimal.TryParse(match.Groups[1].Value, out var refundAmount))
            {
                return refundAmount;
            }

            return 0m;
        }
    }

    private async Task<IDictionary<string, string>[]> ParseAsync(MemoryStream file, string fileExtension)
    {
        if (fileExtension == ".csv")
        {
            return await ParseCsvAsync(file);
        }
        else if (fileExtension == ".xlsx" || fileExtension == ".xls")
        {
            return await ParseExcelAsync(file);
        }
        else
        {
            throw new NotSupportedException("不支持的文件格式");
        }
    }

    private async Task<IDictionary<string, string>[]> ParseCsvAsync(MemoryStream file)
    {
        file.Position = 0;
        using var reader = new StreamReader(file, Encoding.UTF8);

        var config = new CsvConfiguration(CultureInfo.InvariantCulture)
        {
            HasHeaderRecord = true,
            TrimOptions = TrimOptions.Trim
        };

        using var csv = new CsvReader(reader, config);

        // 读取表头
        await csv.ReadAsync();
        csv.ReadHeader();
        var headers = csv.HeaderRecord;

        if (headers == null || headers.Length == 0)
        {
            return Array.Empty<IDictionary<string, string>>();
        }

        var result = new List<IDictionary<string, string>>();

        // 读取数据行
        while (await csv.ReadAsync())
        {
            var row = new Dictionary<string, string>();
            foreach (var header in headers)
            {
                row[header] = csv.GetField(header) ?? string.Empty;
            }

            result.Add(row);
        }

        return result.ToArray();
    }

    private async Task<IDictionary<string, string>[]> ParseExcelAsync(MemoryStream file)
    {
        file.Position = 0;

        // 设置 EPPlus 许可证上下文
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

        using var package = new ExcelPackage(file);
        var worksheet = package.Workbook.Worksheets.FirstOrDefault();

        if (worksheet == null || worksheet.Dimension == null)
        {
            return Array.Empty<IDictionary<string, string>>();
        }

        var rowCount = worksheet.Dimension.End.Row;
        var colCount = worksheet.Dimension.End.Column;

        if (rowCount < 2)
        {
            return Array.Empty<IDictionary<string, string>>();
        }

        // 读取表头（第一行）
        var headers = new List<string>();
        for (int col = 1; col <= colCount; col++)
        {
            var header = worksheet.Cells[1, col].Text?.Trim() ?? string.Empty;
            headers.Add(header);
        }

        var result = new List<IDictionary<string, string>>();

        // 读取数据行（从第二行开始）
        for (int row = 2; row <= rowCount; row++)
        {
            var rowData = new Dictionary<string, string>();
            for (int col = 1; col <= colCount; col++)
            {
                var header = headers[col - 1];
                var value = worksheet.Cells[row, col].Text?.Trim() ?? string.Empty;
                rowData[header] = value;
            }

            result.Add(rowData);
        }

        return await Task.FromResult(result.ToArray());
    }

    private static string[] DateTimeFormats =
    [
        "yyyy-MM-dd",
        "yyyy-MM-dd HH",
        "yyyy-MM-dd HH:mm",
        "yyyy-MM-dd HH:mm:ss",
        "yyyy-M-d",
        "yyyy-M-d HH:mm",
        "yyyy-M-d HH:mm:ss",
        "yyyy/MM/dd",
        "yyyy/MM/dd HH",
        "yyyy/MM/dd HH:mm",
        "yyyy/MM/dd HH:mm:ss",
        "yyyy/M/d",
        "yyyy/M/d HH:mm",
        "yyyy/M/d HH:mm:ss",
        "MM/dd/yyyy",
        "MM/dd/yyyy HH",
        "MM/dd/yyyy HH:mm",
        "MM/dd/yyyy HH:mm:ss",
        "M/d/yyyy",
        "M/d/yyyy HH:mm",
        "M/d/yyyy HH:mm:ss",
        "MM/dd/yy",
        "M/d/yy H:mm",
        "MM/dd/yy HH",
        "MM/dd/yy HH:mm",
        "MM/dd/yy HH:mm:ss",
        "M/d/yy",
        "M/d/yy HH",
        "M/d/yy HH:mm",
        "M/d/yy HH:mm:ss",
        "yyyyMMdd",
        "yyyyMMddHH",
        "yyyyMMddHHmm",
        "yyyyMMddHHmmss",
    ];
}
