/*
 * @Author: Student author@example.com
 * @Date: 2025-01-02 23:22:59
 * @LastEditors: Student author@example.com
 * @LastEditTime: 2025-01-03 18:59:50
 * @FilePath: \LibraryManageSystem\src\Member.cpp
 * @Description: Coding with UTF-8
 *
 * Copyright (c) 2025 by Student, All Rights Reserved.
 */
#include "../include/Member.h"
#include <ctime>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

/**
 * @brief Member类构造函数
 * @param id 用户ID
 * @param name 用户姓名
 * @param phone 手机号码
 * @param password 密码
 * @param type 用户类型(管理员/普通用户)
 */
Member::Member(const std::string &id, const std::string &name, const std::string &phone,
               const std::string &password, MemberType type)
    : id(id), name(name), phone(phone), password(password), type(type)
{
    level = MemberLevel::LEVEL_1;
    creditScore = 100;
    // 初始化其他成员变量
    for (int i = 0; i < 8; i++)
    {
        categoryWeights[i] = 0.0;
    }
}

/**
 * @brief 借阅图书
 * @param bookId 图书ID
 * @return 借阅成功返回true,失败返回false
 */
bool Member::borrowBook(const std::string &bookId)
{
    if (!canBorrowMore())
    {
        return false;
    }

    // 检查是否已借阅该书
    for (int i = 1; i <= borrowedBooks.length(); i++)
    {
        if (std::to_string(borrowedBooks.getPointer(i)->data) == bookId)
        {
            return false;
        }
    }

    borrowedBooks.addNodeToEnd(std::stoi(bookId));
    borrowDates.addNodeToEnd(std::time(nullptr));
    addBorrowRecord(bookId); // 添加借阅记录
    saveBorrowRecords();     // 保存借阅记录
    return true;
}

/**
 * @brief 归还图书
 * @param bookId 图书ID
 * @return 归还成功返回true,失败返回false
 */
bool Member::returnBook(const std::string &bookId)
{
    for (int i = 1; i <= borrowedBooks.length(); i++)
    {
        if (std::to_string(borrowedBooks.getPointer(i)->data) == bookId)
        {
            // 检查是否超期
            time_t borrowDate = borrowDates.getPointer(i)->data;
            time_t now = std::time(nullptr);
            int maxDays = getMaxBorrowDays();

            if ((now - borrowDate) > (maxDays * 24 * 3600))
            {
                // 超期扣分
                updateCreditScore(-5);
            }

            borrowedBooks.deleteNode(i);
            borrowDates.deleteNode(i);

            // 更新借阅记录
            for (auto &record : borrowRecords)
            {
                if (record.bookId == bookId && record.returnDate == 0)
                {
                    record.returnDate = std::time(nullptr);
                    saveBorrowRecords(); // 保存更新后的记录
                    break;
                }
            }

            return true;
        }
    }
    return false;
}

/**
 * @brief 预约图书
 * @param bookId 图书ID
 * @return 预约成功返回true,失败返回false
 */
bool Member::reserveBook(const std::string &bookId)
{
    // 检查预约数量限制（假设最多预约3本）
    if (reservedBooks.length() >= 3)
    {
        return false;
    }

    reservedBooks.addNodeToEnd(std::stoi(bookId));
    return true;
}

/**
 * @brief 检查是否还能继续借书
 * @return 可以继续借书返回true,否则返回false
 */
bool Member::canBorrowMore() const
{
    return borrowedBooks.length() < getMaxBorrowBooks();
}

/**
 * @brief 更新信用分数
 * @param change 分数变化值
 */
void Member::updateCreditScore(int change)
{
    creditScore += change;
    if (creditScore > 100)
        creditScore = 100;
    if (creditScore < 0)
        creditScore = 0;
    recalculateLevel();
}

/**
 * @brief 重新计算会员等级
 */
void Member::recalculateLevel()
{
    if (creditScore >= 90)
    {
        level = MemberLevel::LEVEL_3;
    }
    else if (creditScore >= 70)
    {
        level = MemberLevel::LEVEL_2;
    }
    else
    {
        level = MemberLevel::LEVEL_1;
    }
}

/**
 * @brief 获取最大借阅天数
 * @return 最大借阅天数
 */
int Member::getMaxBorrowDays() const
{
    switch (level)
    {
    case MemberLevel::LEVEL_3:
        return 45;
    case MemberLevel::LEVEL_2:
        return 30;
    default:
        return 15;
    }
}

/**
 * @brief 获取最大可借书数量
 * @return 最大可借书数量
 */
int Member::getMaxBorrowBooks() const
{
    switch (level)
    {
    case MemberLevel::LEVEL_3:
        return 8;
    case MemberLevel::LEVEL_2:
        return 5;
    default:
        return 3;
    }
}

/**
 * @brief 对图书进行评分
 * @param bookId 图书ID
 * @param rating 评分(1-5)
 */
void Member::rateBook(const std::string &bookId, int rating)
{
    if (rating < 1 || rating > 5)
        return;

    // 检查是否在借阅历史中
    bool found = false;
    for (int i = 1; i <= borrowHistory.length(); i++)
    {
        if (std::to_string(borrowHistory.getPointer(i)->data) == bookId)
        {
            found = true;
            break;
        }
    }

    if (found)
    {
        // 存储评分 (使用bookId和rating组合存储)
        bookRatings.addNodeToEnd(std::stoi(bookId) * 10 + rating);
    }
}

/**
 * @brief 更新用户偏好图书类别
 */
void Member::updatePreferredCategories()
{
    // 重置权重
    for (int i = 0; i < 8; i++)
    {
        categoryWeights[i] = 0.0;
    }

    // 根据借阅历史更新权重
    for (int i = 1; i <= borrowHistory.length(); i++)
    {
        std::string bookId = std::to_string(borrowHistory.getPointer(i)->data);
        // 这里需要通过LibrarySystem获取Book对象
        int categoryIndex = i % 8; // 示例：根据实际情况获取图书类别
        categoryWeights[categoryIndex] += 1.0;
    }

    // 归一化权重
    double sum = 0.0;
    for (int i = 0; i < 8; i++)
    {
        sum += categoryWeights[i];
    }
    if (sum > 0)
    {
        for (int i = 0; i < 8; i++)
        {
            categoryWeights[i] /= sum;
        }
    }
}

/**
 * @brief 添加借阅记录
 * @param bookId 图书ID
 */
void Member::addBorrowRecord(const std::string &bookId)
{
    BorrowRecord record;
    record.bookId = bookId;
    record.borrowDate = std::time(nullptr);
    record.dueDate = record.borrowDate + (getMaxBorrowDays() * 24 * 3600);
    record.returnDate = 0; // 初始化为0，表示尚未归还
    borrowRecords.push_back(record);
    saveBorrowRecords(); // 确保记录被保存
}

/**
 * @brief 删除借阅记录
 * @param bookId 图书ID
 */
void Member::removeBorrowRecord(const std::string &bookId)
{
    auto it = std::find_if(borrowRecords.begin(), borrowRecords.end(),
                           [&bookId](const BorrowRecord &record)
                           {
                               return record.bookId == bookId;
                           });
    if (it != borrowRecords.end())
    {
        borrowRecords.erase(it);
    }
}

/**
 * @brief 获取图书应还日期
 * @param bookId 图书ID
 * @return 应还日期的时间戳
 */
time_t Member::getDueDate(const std::string &bookId) const
{
    auto it = std::find_if(borrowRecords.begin(), borrowRecords.end(),
                           [&bookId](const BorrowRecord &record)
                           {
                               return record.bookId == bookId;
                           });
    return it != borrowRecords.end() ? it->dueDate : 0;
}

/**
 * @brief 验证密码
 * @param inputPassword 输入的密码
 * @return 密码正确返回true,错误返回false
 */
bool Member::verifyPassword(const std::string &inputPassword) const
{
    return password == inputPassword;
}

/**
 * @brief 检查是否借阅过某本书
 * @param bookId 图书ID
 * @return 借阅过返回true,否则返回false
 */
bool Member::hasBorrowed(const std::string &bookId) const
{
    for (int i = 1; i <= borrowedBooks.length(); i++)
    {
        if (std::to_string(borrowedBooks.getPointer(i)->data) == bookId)
            return true;
    }
    return false;
}

/**
 * @brief 获取某个图书类别的权重
 * @param category 图书类别
 * @return 该类别的权重值
 */
double Member::getCategoryWeight(BookCategory category) const
{
    return categoryWeights[static_cast<int>(category)];
}

/**
 * @brief 保存借阅记录到文件
 * @return 保存成功返回true,失败返回false
 */
bool Member::saveBorrowRecords() const
{
    // 确保目录存在
#ifdef _WIN32
    std::string cmd = "if not exist \"" + std::string(USER_DATA_DIR) + "\" mkdir \"" + std::string(USER_DATA_DIR) + "\"";
    std::system(cmd.c_str());
#else
    std::string cmd = "mkdir -p \"" + std::string(USER_DATA_DIR) + "\"";
    std::system(cmd.c_str());
#endif

    std::ofstream file(getBorrowRecordsPath());
    if (!file.is_open())
    {
        std::cerr << "创建用户数据失败: " << getBorrowRecordsPath() << std::endl;
        return false;
    }

    // 写入CSV头
    file << "BookId,BorrowDate,DueDate,ReturnDate\n";
    for (const auto &record : borrowRecords)
    {
        file << record.bookId << ","
             << record.borrowDate << ","
             << record.dueDate << ","
             << record.returnDate << "\n";
    }
    file.close();
    return true;
}

/**
 * @brief 从文件加载借阅记录
 * @return 加载成功返回true,失败返回false
 */
bool Member::loadBorrowRecords()
{
    std::ifstream file(getBorrowRecordsPath());
    if (!file.is_open())
        return false;

    borrowRecords.clear();
    std::string line;
    std::getline(file, line); // 跳过CSV头

    while (std::getline(file, line))
    {
        std::stringstream ss(line);
        std::string bookId, borrowDate, dueDate, returnDate;

        std::getline(ss, bookId, ',');
        std::getline(ss, borrowDate, ',');
        std::getline(ss, dueDate, ',');
        std::getline(ss, returnDate, ',');

        BorrowRecord record;
        record.bookId = bookId;
        record.borrowDate = std::stoll(borrowDate);
        record.dueDate = std::stoll(dueDate);
        if (!returnDate.empty())
        {
            record.returnDate = std::stoll(returnDate);
        }
        borrowRecords.push_back(record);
    }
    return true;
}

/**
 * @brief 更新借阅记录
 */
void Member::updateBorrowRecords()
{
    time_t now = std::time(nullptr);
    bool needsSave = false;

    for (auto &record : borrowRecords)
    {
        if (record.returnDate == 0) // 未归还的图书
        {
            // 如果已超期，更新信用分
            if (now > record.dueDate && !record.returnDate)
            {
                int overdueDays = (now - record.dueDate) / (24 * 3600);
                updateCreditScore(-overdueDays); // 每超期一天扣1分
                needsSave = true;
            }
        }
    }

    if (needsSave)
    {
        saveBorrowRecords();
    }
}

/**
 * @brief 更新个人信息
 * @param newName 新姓名
 * @param newPhone 新手机号
 */
void Member::updatePersonalInfo(const std::string &newName, const std::string &newPhone)
{
    if (!newName.empty())
    {
        name = newName;
    }
    if (!newPhone.empty())
    {
        phone = newPhone;
    }
}

/**
 * @brief 更新密码
 * @param newPassword 新密码
 */
void Member::updatePassword(const std::string &newPassword)
{
    if (!newPassword.empty())
    {
        password = newPassword;
    }
}

/**
 * @brief MemberManager构造函数
 * @param filename 用户数据文件路径
 */
MemberManager::MemberManager(const std::string &filename) : dataFile(filename)
{
    std::cout << "初始化 MemberManager，数据文件: " << filename << std::endl;
    loadFromFile();
    std::cout << "加载完成，当前用户数: " << members.length() << std::endl;
}

/**
 * @brief MemberManager析构函数
 */
MemberManager::~MemberManager() {}

/**
 * @brief 添加新会员
 * @param member 会员对象指针
 * @return 添加成功返回true,失败返回false
 */
bool MemberManager::addMember(Member *member)
{
    std::cout << "正在注册账户: " << member->getId() << std::endl;

    // 检查ID和手机号是否已存在
    if (findMember(member->getId()) || findMemberByPhone(member->getPhone()))
    {
        std::cout << "ID或手机号已经存在" << std::endl;
        return false;
    }

    try
    {
        members.addNodeToEnd(reinterpret_cast<intptr_t>(member));
        std::cout << "保存成功" << std::endl;
        saveToFile(); // 保存到文件
        // 创建用户的借阅记录文件
        if (!member->saveBorrowRecords())
        {
            std::cout << "加载借阅记录失败" << std::endl;
            members.deleteNode(members.length()); // 回滚添加操作
            return false;
        }
        return true;
    }
    catch (const std::exception &e)
    {
        std::cout << "注册用户时发生异常: " << e.what() << std::endl;
        return false;
    }
}

/**
 * @brief 根据ID查找会员
 * @param id 会员ID
 * @return 找到返回会员指针,未找到返回nullptr
 */
Member *MemberManager::findMember(const std::string &id) const
{
    if (members.length() <= 0)
    {
        return nullptr;
    }

    for (int i = 1; i <= members.length(); i++)
    {
        const ListNode *node = members.getPointer(i);
        if (!node)
        {
            continue;
        }

        Member *member = reinterpret_cast<Member *>(node->data);
        if (!member)
        {
            continue;
        }

        if (member->getId() == id)
        {
            return member;
        }
    }

    return nullptr;
}

/**
 * @brief 验证用户身份
 * @param id 用户ID
 * @param password 密码
 * @return 验证成功返回会员指针,失败返回nullptr
 */
Member *MemberManager::authenticate(const std::string &id, const std::string &password)
{
    Member *member = findMember(id);
    if (!member)
    {
        return nullptr;
    }

    if (member->verifyPassword(password))
    {
        return member;
    }

    return nullptr;
}

/**
 * @brief 显示所有会员信息
 */
void MemberManager::displayAllMembers() const
{
    for (int i = 1; i <= members.length(); i++)
    {
        Member *member = reinterpret_cast<Member *>(members.getPointer(i)->data);
        std::cout << "ID: " << member->getId()
                  << ", 姓名: " << member->getName()
                  << ", 手机: " << member->getPhone()
                  << ", 等级: " << static_cast<int>(member->getLevel())
                  << ", 信用分: " << member->getCreditScore() << std::endl;
    }
}

/**
 * @brief 保存会员数据到文件
 * @return 保存成功返回true,失败返回false
 */
bool MemberManager::saveToFile() const
{
    std::ofstream file(dataFile);
    if (!file.is_open())
        return false;

    for (int i = 1; i <= members.length(); i++)
    {
        Member *member = reinterpret_cast<Member *>(members.getPointer(i)->data);
        file << member->getId() << ","
             << member->getName() << ","
             << member->getPhone() << ","
             << member->getPassword() << ","
             << (member->getType() == MemberType::ADMIN ? "ADMIN" : "NORMAL") << ","
             << member->getCreditScore() << "\n";
    }
    return true;
}

/**
 * @brief 从文件加载会员数据
 * @return 加载成功返回true,失败返回false
 */
bool MemberManager::loadFromFile()
{
    std::ifstream file(dataFile);
    if (!file.is_open())
    {
        return false;
    }

    members = LinkList();

    std::string line;
    while (std::getline(file, line))
    {
        std::stringstream ss(line);
        std::string id, name, phone, password, type, score;

        if (!std::getline(ss, id, ',') || !std::getline(ss, name, ',') ||
            !std::getline(ss, phone, ',') || !std::getline(ss, password, ',') ||
            !std::getline(ss, type, ',') || !std::getline(ss, score, '\n'))
        {
            continue;
        }

        Member *member = new Member(id, name, phone, password,
                                    type == "ADMIN" ? MemberType::ADMIN : MemberType::NORMAL);

        try
        {
            member->updateCreditScore(std::stoi(score) - 100);
        }
        catch (...)
        {
            member->updateCreditScore(0);
        }

        intptr_t memberPtr = reinterpret_cast<intptr_t>(member);
        if (memberPtr != 0)
        {
            members.addNodeToEnd(memberPtr);
        }
        else
        {
            delete member;
        }
    }

    return true;
}

/**
 * @brief 根据手机号查找会员
 * @param phone 手机号
 * @return 找到返回会员指针,未找到返回nullptr
 */
Member *MemberManager::findMemberByPhone(const std::string &phone) const
{
    for (int i = 1; i <= members.length(); i++)
    {
        Member *member = reinterpret_cast<Member *>(members.getPointer(i)->data);
        if (member->getPhone() == phone)
            return member;
    }
    return nullptr;
}

/**
 * @brief 获取所有有超期图书的会员
 * @return 包含超期会员的链表
 */
LinkList MemberManager::getOverdueMembers() const
{
    LinkList result;
    for (int i = 1; i <= members.length(); i++)
    {
        Member *member = reinterpret_cast<Member *>(members.getPointer(i)->data);
        // 检查是否有超期图书
        const auto &records = member->getBorrowRecords();
        for (const auto &record : records)
        {
            if (std::time(nullptr) > record.dueDate)
            {
                result.addNodeToEnd(reinterpret_cast<intptr_t>(member));
                break;
            }
        }
    }
    return result;
}

/**
 * @brief 使用二分查找来查找会员
 * @param id 要查找的会员ID
 * @return 如果找到返回Member指针,否则返回nullptr
 * @note 这是一个冗余实现，需要先对members按ID排序
 */
Member *MemberManager::findMemberBinary(const std::string &id) const
{
    // 创建临时数组存储排序后的会员指针
    int length = members.length();
    Member **sortedMembers = new Member *[length];
    for (int i = 1; i <= length; i++)
    {
        sortedMembers[i - 1] = reinterpret_cast<Member *>(members.getPointer(i)->data);
    }

    // 冒泡排序按id排序
    for (int i = 0; i < length - 1; i++)
    {
        for (int j = 0; j < length - i - 1; j++)
        {
            if (sortedMembers[j]->getId() > sortedMembers[j + 1]->getId())
            {
                Member *temp = sortedMembers[j];
                sortedMembers[j] = sortedMembers[j + 1];
                sortedMembers[j + 1] = temp;
            }
        }
    }

    // 二分查找
    int left = 0;
    int right = length - 1;
    Member *result = nullptr;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        std::string midId = sortedMembers[mid]->getId();

        if (midId == id)
        {
            result = sortedMembers[mid];
            break;
        }

        if (midId < id)
        {
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    // 释放临时数组
    delete[] sortedMembers;
    return result;
}

/**
 * @brief 使用二分查找来通过手机号查找会员
 * @param phone 要查找的手机号
 * @return 如果找到返回Member指针,否则返回nullptr
 * @note 这是一个冗余实现，需要先对members按手机号排序
 */
Member *MemberManager::findMemberByPhoneBinary(const std::string &phone) const
{
    // 创建临时数组存储排序后的会员指针
    int length = members.length();
    Member **sortedMembers = new Member *[length];
    for (int i = 1; i <= length; i++)
    {
        sortedMembers[i - 1] = reinterpret_cast<Member *>(members.getPointer(i)->data);
    }

    // 冒泡排序按phone排序
    for (int i = 0; i < length - 1; i++)
    {
        for (int j = 0; j < length - i - 1; j++)
        {
            if (sortedMembers[j]->getPhone() > sortedMembers[j + 1]->getPhone())
            {
                Member *temp = sortedMembers[j];
                sortedMembers[j] = sortedMembers[j + 1];
                sortedMembers[j + 1] = temp;
            }
        }
    }

    // 二分查找
    int left = 0;
    int right = length - 1;
    Member *result = nullptr;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        std::string midPhone = sortedMembers[mid]->getPhone();

        if (midPhone == phone)
        {
            result = sortedMembers[mid];
            break;
        }

        if (midPhone < phone)
        {
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    // 释放临时数组
    delete[] sortedMembers;
    return result;
}

/**
 * @brief 计算字符串的BKDR哈希值
 * @param str 要计算哈希值的字符串
 * @return 哈希值
 * @note BKDR哈希算法是一种经典的字符串哈希算法,具有以下特点:
 *       1. 计算速度快,只需要遍历一次字符串
 *       2. 冲突概率较低,通过选择合适的seed值可以进一步降低冲突
 *       3. 分布均匀,生成的哈希值在整个取值范围内分布相对均匀
 *       4. 雪崩效应好,输入的微小变化会导致输出的显著变化
 */
unsigned int MemberManager::BKDRHash(const std::string &str) const
{
    unsigned int seed = 131; // 种子数,可选用31,131,1313等质数,质数作为种子可以让哈希值分布更均匀
    unsigned int hash = 0;   // 初始化哈希值

    // 对字符串中的每个字符进行处理
    for (char c : str)
    {
        // 哈希计算公式: hash = hash * seed + 当前字符
        // 这样可以保证字符串中每个位置的字符都对最终哈希值有贡献
        hash = hash * seed + c;
    }

    return hash;
}

/**
 * @brief 使用哈希表查找会员
 * @param name 用户名
 * @return 如果找到返回Member指针,否则返回nullptr
 * @note 这是一个基于哈希的冗余实现,使用拉链法处理哈希冲突
 *       时间复杂度:
 *       - 平均情况: O(1)
 *       - 最坏情况: O(n) (当所有元素都哈希到同一个桶时)
 */
Member *MemberManager::findMemberByNameHash(const std::string &name) const
{
    // 定义哈希表大小为1024,这是一个权衡值:
    // - 太小会增加冲突概率
    // - 太大会浪费内存空间
    const int TABLE_SIZE = 1024;
    Member **hashTable[TABLE_SIZE];       // 哈希表,每个位置存储一个动态数组(桶)
    int hashSizes[TABLE_SIZE] = {0};      // 记录每个桶当前存储的元素数量
    int hashCapacities[TABLE_SIZE] = {0}; // 记录每个桶的当前容量

    // 初始化哈希表,将所有桶指针设为nullptr
    for (int i = 0; i < TABLE_SIZE; i++)
    {
        hashTable[i] = nullptr;
    }

    // 将所有会员插入哈希表
    for (int i = 1; i <= members.length(); i++)
    {
        Member *member = reinterpret_cast<Member *>(members.getPointer(i)->data);
        // 计算哈希值并取模,确保在表大小范围内
        unsigned int hash = BKDRHash(member->getName()) % TABLE_SIZE;

        // 如果当前桶已满或未分配,需要分配或扩展空间
        if (hashSizes[hash] >= hashCapacities[hash])
        {
            // 使用倍增策略扩展容量,初始容量为4
            int newCapacity = hashCapacities[hash] == 0 ? 4 : hashCapacities[hash] * 2;
            Member **newBucket = new Member *[newCapacity];

            // 将原有数据复制到新空间
            for (int j = 0; j < hashSizes[hash]; j++)
            {
                newBucket[j] = hashTable[hash][j];
            }

            // 释放旧空间并更新指针和容量
            delete[] hashTable[hash];
            hashTable[hash] = newBucket;
            hashCapacities[hash] = newCapacity;
        }

        // 将会员指针添加到对应的桶中
        hashTable[hash][hashSizes[hash]++] = member;
    }

    // 查找目标会员
    unsigned int hash = BKDRHash(name) % TABLE_SIZE;
    // 在对应的桶中线性查找
    for (int i = 0; i < hashSizes[hash]; i++)
    {
        if (hashTable[hash][i]->getName() == name)
        {
            // 找到目标会员后,清理所有动态分配的内存
            for (int i = 0; i < TABLE_SIZE; i++)
            {
                delete[] hashTable[i];
            }
            return hashTable[hash][i];
        }
    }

    // 未找到目标会员,清理所有动态分配的内存
    for (int i = 0; i < TABLE_SIZE; i++)
    {
        delete[] hashTable[i];
    }
    return nullptr;
}
