-- 假设当前操作的管理员ID
-- 在实际应用中，这个ID会从登录会话中获取
-- SELECT admin_id INTO v_admin_id FROM admins WHERE emp_no = 'A001'; -- 示例：获取张管理的ID
-- 为了简化示例，我们直接使用数字，假设 admin_id=1 是一个有效管理员
-- 请根据你的 admins 表实际数据替换

----------------------------------------------------------------------
-- (1). 图书信息管理（增删改查、批量导入）
----------------------------------------------------------------------

-- A. 新增图书 (Create)
INSERT INTO books (isbn, title, authors, publisher, publish_date, price, classification_no, location, total_copies, available_copies, description, cover_url)
VALUES
('9787121408881', 'Effective Java 中文版 (原书第3版)', ARRAY['Joshua Bloch'], '机械工业出版社', '2019-01-01', 119.00, 'TP312JA', 'A区3架5层', 5, 5, 'Java程序员必读的经典著作，包含90个实用条目。', 'http://example.com/cover_effective_java.jpg');

-- B. 查询图书 (Read)
-- B1. 按ISBN精确查询
SELECT * FROM books WHERE isbn = '9787111624927';

-- B2. 按书名模糊查询 (使用 trigram 索引 idx_books_title_trgm)
SELECT * FROM books WHERE title % '计算机'; -- 查询包含“计算机”的
SELECT * FROM books WHERE title ILIKE '%系统%'; -- 不区分大小写查询包含“系统”的

-- B3. 按作者查询 (使用 GIN 索引 idx_books_authors_gin)
SELECT * FROM books WHERE authors @> ARRAY['吴军']; -- 查询作者包含“吴军”的

-- B4. 按分类号查询
SELECT * FROM books WHERE classification_no = 'TP301';

-- B5. 查看所有“正常”状态的图书
SELECT * FROM books WHERE status = 'normal';

-- C. 修改图书信息 (Update)
-- 假设要修改 book_id 为 1 的图书信息
UPDATE books
SET
    price = 145.00,
    location = 'A区2架3层 (更新)',
    description = '计算机系统的经典之作，最新修订版。',
    updated_at = now()
WHERE book_id = 1; -- 假设 book_id 为 1 的是《深入理解计算机系统》

-- 修改图书状态 (例如，将一本损坏的书修复后改为正常)
UPDATE books
SET status = 'normal', available_copies = available_copies + 1 -- 如果之前因损坏不可借
WHERE isbn = '9787208159659' AND status = 'damaged'; -- 假设《三体全集》某本修复

-- D. 删除图书 (Delete) - 谨慎操作，通常建议逻辑删除或下架
-- 注意：如果该书有关联的借阅记录、预约记录、评价记录，且外键设置了 ON DELETE CASCADE，则这些关联记录也会被删除。
-- 如果设置了 ON DELETE RESTRICT (或默认)，且存在关联记录，则删除会失败。
-- 你的表结构中，borrow_records, reservations, reviews 都对 book_id 设置了 ON DELETE CASCADE。
-- DELETE FROM books WHERE isbn = '9780132350884'; -- 删除已下架的《Clean Code》

-- 更好的方式是“下架”
UPDATE books
SET status = 'removed', available_copies = 0
WHERE isbn = '9780132350884';

-- E. 批量导入图书 (Batch Import)
INSERT INTO books (isbn, title, authors, publisher, total_copies, available_copies) VALUES
('ISBN001', '批量导入书1', ARRAY['作者X'], '出版社A', 2, 2),
('ISBN002', '批量导入书2', ARRAY['作者Y', '作者Z'], '出版社B', 3, 3);


----------------------------------------------------------------------
-- (2). 学生账户管理
----------------------------------------------------------------------
-- A. 新增学生账户
INSERT INTO students (stu_no, name, gender, department, major, grade, class, phone, email, max_borrow)
VALUES
('S2024001', '刘新', 'M', '物理学院', '应用物理', '2024', '01班', '13600001111', 'liuxin@example.com', (SELECT setting_value::int FROM system_settings WHERE setting_key='max_borrow_default'));

-- B. 查询学生账户
-- B1. 按学号查询
SELECT * FROM students WHERE stu_no = 'S2023001';

-- B2. 按姓名模糊查询
SELECT * FROM students WHERE name LIKE '张%';

-- B3. 查询某院系所有学生
SELECT * FROM students WHERE department = '计算机学院';

-- C. 修改学生账户信息
-- C1. 修改学生联系方式
UPDATE students
SET phone = '13511112222', email = 'new_zhangsan@example.com'
WHERE stu_no = 'S2023001';

-- C2. 修改学生账户状态 (例如：解挂、冻结/解冻 - 冻结通常由触发器完成，但管理员也可手动操作)
-- 解挂
UPDATE students SET account_status = 'active' WHERE stu_no = 'S2023005' AND account_status = 'reported';
-- 手动冻结 (如果业务需要)
UPDATE students SET account_status = 'frozen' WHERE stu_no = 'S2023001';
-- 手动解冻 (例如，学生缴清罚款后，触发器未及时更新或有特殊情况)
-- 首先确保罚款已清或问题已解决
-- UPDATE fines SET status = 'paid' WHERE student_id = (SELECT student_id FROM students WHERE stu_no = 'S2023005') AND status = 'unpaid';
-- 然后（如果触发器没有将所有欠款清零后的账户自动激活）
-- UPDATE students SET account_status = 'active' WHERE stu_no = 'S2023005' AND account_status = 'frozen';

-- C3. 修改学生最大借阅量
UPDATE students SET max_borrow = 12 WHERE stu_no = 'S2023001';


----------------------------------------------------------------------
-- (3). 处理借阅、归还、续借请求
----------------------------------------------------------------------
-- A. 处理借阅请求 (学生在前台操作，管理员后台处理或确认)
-- 假设学生 (stu_no='S2023002', 李四) 要借阅图书 (isbn='9787111624927', 深入理解计算机系统)
-- 前提检查 (通常在应用层完成，但也可在存储过程中封装):
-- 1. 图书可借: SELECT available_copies, status FROM books WHERE isbn = '9787111624927'; (available_copies > 0 and status = 'normal')
-- 2. 学生账户正常: SELECT account_status FROM students WHERE stu_no = 'S2023002'; (account_status = 'active')
-- 3. 学生未超借阅上限: SELECT current_borrow, max_borrow FROM students WHERE stu_no = 'S2023002'; (current_borrow < max_borrow)

DO $$
DECLARE
    v_student_id bigint;
    v_book_id bigint;
    v_available_copies int;
    v_book_status book_status_enum;
    v_account_status acct_status_enum;
    v_current_borrow int;
    v_max_borrow int;
    v_borrow_duration int;
BEGIN
    SELECT student_id, account_status, current_borrow, max_borrow INTO v_student_id, v_account_status, v_current_borrow, v_max_borrow
    FROM students WHERE stu_no = 'S2023002';

    SELECT book_id, available_copies, status INTO v_book_id, v_available_copies, v_book_status
    FROM books WHERE isbn = '9787111624927';

    IF NOT FOUND THEN RAISE EXCEPTION '学生或图书不存在'; END IF;

    IF v_book_status != 'normal' THEN RAISE EXCEPTION '图书状态异常，不可借阅: %', v_book_status; END IF;
    IF v_available_copies <= 0 THEN RAISE EXCEPTION '图书已无馆藏可借'; END IF;
    IF v_account_status != 'active' THEN RAISE EXCEPTION '学生账户状态异常，不可借阅: %', v_account_status; END IF;
    IF v_current_borrow >= v_max_borrow THEN RAISE EXCEPTION '已达到最大借阅量'; END IF;

    SELECT setting_value::int INTO v_borrow_duration FROM system_settings WHERE setting_key = 'borrow_duration_days';

    INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status)
    VALUES (v_book_id, v_student_id, current_date, current_date + (v_borrow_duration || ' days')::interval, 'borrowed');

    RAISE NOTICE '借阅成功! Book ID: %, Student ID: %', v_book_id, v_student_id;
    -- 触发器 trg_sync_book_student 会自动更新 books.available_copies 和 students.current_borrow
END $$;

-- B. 处理归还请求
-- 假设要归还 borrow_id 为 (假设是1，根据实际情况查询得到) 的借阅记录
-- SELECT borrow_id FROM borrow_records br JOIN students s ON br.student_id = s.student_id JOIN books b ON br.book_id = b.book_id
-- WHERE s.stu_no='S2023001' AND b.isbn='9787111624927' AND br.status IN ('borrowed', 'overdue'); (假设这是张三借的《深入理解计算机系统》)

-- 获取特定借阅记录ID (例如，张三当前借阅的《深入理解计算机系统》)
DO $$
DECLARE
    v_borrow_id bigint;
BEGIN
    SELECT br.borrow_id INTO v_borrow_id
    FROM borrow_records br
    JOIN students s ON br.student_id = s.student_id
    JOIN books b ON br.book_id = b.book_id
    WHERE s.stu_no = 'S2023001' AND b.isbn = '9787111624927' AND br.status IN ('borrowed', 'overdue')
    ORDER BY br.borrow_date DESC LIMIT 1; -- 获取最近一次未还的

    IF NOT FOUND THEN
        RAISE NOTICE '未找到该学生对应的此书的当前借阅记录。';
        RETURN;
    END IF;

    RAISE NOTICE '正在归还 borrow_id: %', v_borrow_id;

    UPDATE borrow_records
    SET
        status = 'returned',
        return_date = current_date
    WHERE borrow_id = v_borrow_id;
    -- 触发器 trg_calc_fine 会在逾期归还时自动记录罚款
    -- 触发器 trg_sync_book_student 会自动更新 books.available_copies 和 students.current_borrow
    RAISE NOTICE '归还操作完成。';
END $$;


-- C. 处理续借请求
-- 假设要续借 borrow_id 为 (假设是2，李四借的《数学之美》) 的借阅记录
-- 续借条件检查 (应用层或存储过程):
-- 1. 图书未被其他人预约: SELECT 1 FROM reservations WHERE book_id = _book_id_ AND status = 'waiting'; (应为空)
-- 2. 未超最大续借次数: SELECT renew_times FROM borrow_records WHERE borrow_id = _borrow_id_;
--    (renew_times < (SELECT setting_value::int FROM system_settings WHERE setting_key = 'max_renew_times'))
-- 3. 学生账户正常，图书未逾期等。

DO $$
DECLARE
    v_borrow_id bigint;
    v_book_id bigint;
    v_renew_times int;
    v_max_renew_times int;
    v_is_reserved int;
    v_borrow_duration int;
    v_current_due_date date;
    v_current_status borrow_status_enum;
BEGIN
    -- 假设李四 (S2023002) 续借《数学之美》 (isbn='9787030598007')
    SELECT br.borrow_id, br.book_id, br.renew_times, br.due_date, br.status
    INTO v_borrow_id, v_book_id, v_renew_times, v_current_due_date, v_current_status
    FROM borrow_records br
    JOIN students s ON br.student_id = s.student_id
    JOIN books b ON br.book_id = b.book_id
    WHERE s.stu_no = 'S2023002' AND b.isbn = '9787030598007' AND br.status = 'borrowed' -- 通常只能续借未逾期的
    ORDER BY br.borrow_date DESC LIMIT 1;

    IF NOT FOUND THEN RAISE EXCEPTION '未找到该借阅记录或记录状态不符。'; END IF;
    IF v_current_status = 'overdue' THEN RAISE EXCEPTION '图书已逾期，不可续借，请先处理逾期。'; END IF;


    SELECT setting_value::int INTO v_max_renew_times FROM system_settings WHERE setting_key = 'max_renew_times';
    SELECT setting_value::int INTO v_borrow_duration FROM system_settings WHERE setting_key = 'borrow_duration_days';

    IF v_renew_times >= v_max_renew_times THEN
        RAISE EXCEPTION '已达到最大续借次数 (%)', v_max_renew_times;
    END IF;

    SELECT count(*) INTO v_is_reserved FROM reservations
    WHERE book_id = v_book_id AND status = 'waiting'
    AND student_id != (SELECT student_id FROM students WHERE stu_no = 'S2023002'); -- 排除自己的预约

    IF v_is_reserved > 0 THEN
        RAISE EXCEPTION '该图书已被他人预约，不可续借。';
    END IF;

    UPDATE borrow_records
    SET
        due_date = v_current_due_date + (v_borrow_duration || ' days')::interval, -- 从当前应还日期开始延长
        renew_times = v_renew_times + 1
    WHERE borrow_id = v_borrow_id;

    RAISE NOTICE '续借成功! Borrow ID: %，新应还日期: %', v_borrow_id, (SELECT due_date FROM borrow_records WHERE borrow_id=v_borrow_id);
END $$;


----------------------------------------------------------------------
-- (4). 管理预约队列
----------------------------------------------------------------------
-- A. 查看某本图书的预约队列 (例如 book_id = 7, Java核心技术)
SELECT r.reservation_id, r.reserve_date, r.status, s.stu_no, s.name as student_name, s.email
FROM reservations r
JOIN students s ON r.student_id = s.student_id
WHERE r.book_id = 7 AND r.status = 'waiting' -- 假设book_id 7是《Java核心技术 卷I》
ORDER BY r.reserve_date ASC; -- 按预约日期升序，先预约的在前

-- B. 处理到书通知 (当一本被预约的书归还后)
-- 假设 book_id = 7 的书有副本归还，管理员通知队列中的第一个学生
-- B1. 找到第一个等待的学生
DO $$
DECLARE
    v_reservation_id bigint;
    v_student_id bigint;
    v_book_id int := 7; -- 假设是 Java 核心技术
    v_reservation_expiry_days int;
BEGIN
    SELECT reservation_id, student_id INTO v_reservation_id, v_student_id
    FROM reservations
    WHERE book_id = v_book_id AND status = 'waiting'
    ORDER BY reserve_date ASC
    LIMIT 1;

    IF FOUND THEN
        SELECT setting_value::int INTO v_reservation_expiry_days
        FROM system_settings WHERE setting_key = 'reservation_expiry_days';

        UPDATE reservations
        SET status = 'available' -- (可以增加一个 notified_at timestamp 和 available_until timestamp 字段)
        --  available_until = current_timestamp + (v_reservation_expiry_days || ' days')::interval -- (如果表有此字段)
        WHERE reservation_id = v_reservation_id;
        RAISE NOTICE '已通知学生ID % (预约ID %) 图书 % 可取。', v_student_id, v_reservation_id, v_book_id;
        -- 实际应用中会发送邮件/短信
    ELSE
        RAISE NOTICE '图书 % 没有等待中的预约。', v_book_id;
    END IF;
END $$;

-- C. 学生未在规定时间内取书，预约自动或手动过期
UPDATE reservations
SET status = 'expired'
WHERE status = 'available' AND reservation_id = _reservation_id_ ;
-- AND available_until < current_timestamp; -- (如果表有 available_until 字段)

-- D. 管理员取消某个预约 (例如，学生请求取消)
UPDATE reservations
SET status = 'cancelled'
WHERE reservation_id = _reservation_id_ ; -- 替换为实际预约ID


----------------------------------------------------------------------
-- (5). 处理图书遗失、损坏等异常情况
----------------------------------------------------------------------
-- A. 处理图书遗失
-- 假设学生 (stu_no='S2022006', 周八) 遗失了图书 (isbn='9787559620187', 明朝那些事儿)
-- A1. 更新借阅记录状态 (如果该书是被借阅后遗失的)
--     你已经在测试数据中插入了一条 borrow_records 状态为 'lost' 的记录，这里假设是管理员新发现的遗失
DO $$
DECLARE
    v_student_id bigint;
    v_book_id bigint;
    v_borrow_id bigint;
    v_book_price numeric;
    v_admin_id bigint := (SELECT admin_id FROM admins WHERE emp_no = 'A002'); -- 操作管理员ID
BEGIN
    SELECT student_id INTO v_student_id FROM students WHERE stu_no = 'S2022006';
    SELECT book_id, price INTO v_book_id, v_book_price FROM books WHERE isbn = '9787559620187';

    -- 查找该学生对这本书的未还借阅记录
    SELECT borrow_id INTO v_borrow_id
    FROM borrow_records
    WHERE student_id = v_student_id AND book_id = v_book_id AND status IN ('borrowed', 'overdue')
    LIMIT 1;

    IF FOUND THEN
        UPDATE borrow_records SET status = 'lost' WHERE borrow_id = v_borrow_id;
        RAISE NOTICE '借阅记录 % 已更新为遗失。', v_borrow_id;
    ELSE
        RAISE NOTICE '未找到该学生对此书的当前借阅记录，可能是在馆藏中发现遗失。';
    END IF;

    -- A2. 更新图书信息状态和可借数量 (如果这本书之前是可借的)
    -- total_copies 一般不变，除非彻底报废且不再补充
    UPDATE books
    SET
        status = 'lost', -- 如果整本书遗失
        available_copies = GREATEST(0, available_copies - 1) -- 确保可借不为负
    WHERE book_id = v_book_id AND status != 'lost'; -- 避免重复操作，如果已是lost就不再减available_copies

    -- A3. 生成罚款记录 (按书价赔偿)
    INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id)
    VALUES (v_student_id, v_book_price, '遗失图书《明朝那些事儿》(ISBN:9787559620187)', 'unpaid', current_date, v_admin_id);
    RAISE NOTICE '遗失罚款已记录。';
    -- 触发器 trg_freeze_account 会检查是否需要冻结账户
    -- 触发器 trg_sync_book_student 会因为 borrow_records 更新而调整 current_borrow
END $$;

-- B. 处理图书损坏
-- 假设发现馆藏图书 (isbn='9787208159659', 三体全集) 有一本损坏，需要记录并可能罚款最后借阅人
DO $$
DECLARE
    v_book_id bigint;
    v_last_borrower_student_id bigint;
    v_damage_fine_amount numeric := 20.00; -- 损坏赔偿金额
    v_admin_id bigint := (SELECT admin_id FROM admins WHERE emp_no = 'A002');
BEGIN
    SELECT book_id INTO v_book_id FROM books WHERE isbn = '9787208159659';

    -- B1. 更新图书状态，如果损坏到不可借阅，减少可借数量
    UPDATE books
    SET
        status = 'damaged',
        available_copies = GREATEST(0, available_copies - 1) -- 如果损坏导致不可借
    WHERE book_id = v_book_id;
    RAISE NOTICE '图书 % 状态已更新为损坏。', v_book_id;

    -- B2. (可选) 查找最后借阅人并生成罚款
    SELECT student_id INTO v_last_borrower_student_id
    FROM borrow_records
    WHERE book_id = v_book_id AND return_date IS NOT NULL
    ORDER BY return_date DESC
    LIMIT 1;

    IF FOUND THEN
        INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id)
        VALUES (v_last_borrower_student_id, v_damage_fine_amount, '损坏图书《三体全集》(ISBN:9787208159659)', 'unpaid', current_date, v_admin_id);
        RAISE NOTICE '已向最后借阅人 (学生ID: %) 记录损坏罚款。', v_last_borrower_student_id;
        -- 触发器 trg_freeze_account
    ELSE
        RAISE NOTICE '未找到该书的最后借阅人，或为馆藏期间损坏。';
    END IF;
END $$;

-- C. 图书下架 (例如，图书过于陈旧或残破不再流通)
UPDATE books
SET status = 'removed', available_copies = 0
WHERE isbn = 'ISBN_TO_BE_REMOVED';


----------------------------------------------------------------------
-- (6). 设置和管理罚款规则 (主要通过 system_settings 表)
----------------------------------------------------------------------
-- A. 查看当前罚款规则
SELECT * FROM system_settings WHERE setting_key LIKE 'fine%';

-- B. 修改每日逾期罚款金额
UPDATE system_settings
SET setting_value = '0.30' -- 修改为每天0.3元
WHERE setting_key = 'fine_per_day';

-- C. 修改欠款冻结账户的阈值
UPDATE system_settings
SET setting_value = '15.00' -- 修改为欠款15元冻结
WHERE setting_key = 'freeze_threshold';

-- D. 添加新的罚款规则 (如果系统支持更复杂的规则，可能需要修改表结构或增加新表)
-- 当前设计下，罚款规则比较简单，主要就是每日费率。


----------------------------------------------------------------------
-- (7). 生成各类统计报表 (主要使用视图和聚合查询)
----------------------------------------------------------------------
-- A. 查看热门图书 (借阅量前20，使用视图)
SELECT * FROM v_hot_books;

-- B. 查看各院系借阅统计 (使用视图)
SELECT * FROM v_dept_borrow_stats;

-- C. 查看图书逾期情况 (使用视图)
SELECT vd.*, b.title AS book_title, s.name AS student_name, s.phone AS student_phone
FROM v_overdue_details vd
JOIN books b ON vd.book_id = b.book_id
JOIN students s ON vd.student_id = s.student_id;

-- D. 自定义报表：某一时段内各类图书的借阅次数
SELECT
    b.classification_no, 
    COUNT(br.borrow_id) AS borrow_count
FROM borrow_records br
JOIN books b ON br.book_id = b.book_id
WHERE br.borrow_date BETWEEN '2025-01-01' AND '2025-12-31' -- 示例时间段
GROUP BY b.classification_no
ORDER BY borrow_count DESC;

-- E. 自定义报表：每月借阅总量趋势
SELECT
    to_char(borrow_date, 'YYYY-MM') AS borrow_month,
    COUNT(borrow_id) AS total_borrows
FROM borrow_records
GROUP BY borrow_month
ORDER BY borrow_month;

-- F. 调用存储过程生成定期报表 (如果 sp_generate_circulation_stats 是设计为手动触发的)
-- SELECT sp_generate_circulation_stats();
-- 然后查询报表数据
-- SELECT * FROM circulation_stats ORDER BY stat_date DESC;

----------------------------------------------------------------------
-- (8). 系统参数设置 (主要通过 system_settings 表)
----------------------------------------------------------------------
-- A. 查看所有系统参数
SELECT * FROM system_settings;

-- B. 修改默认最大借阅量
UPDATE system_settings
SET setting_value = '8'
WHERE setting_key = 'max_borrow_default';
-- 注意：这只影响未来新建学生账户的默认值，或在 sp_init_students 中使用此值批量更新。
-- 已有学生的 max_borrow 需要单独修改，或在初始化脚本中覆盖。

-- C. 修改默认借阅期限（天数）
UPDATE system_settings
SET setting_value = '25'
WHERE setting_key = 'borrow_duration_days';

-- D. 修改最大续借次数
UPDATE system_settings
SET setting_value = '1'
WHERE setting_key = 'max_renew_times';

-- E. 修改预约保留天数
UPDATE system_settings
SET setting_value = '2'
WHERE setting_key = 'reservation_expiry_days';

-- F. 添加新的系统参数 (如果应用需要)
-- INSERT INTO system_settings (setting_key, setting_value)
-- VALUES ('new_feature_xyz_enabled', 'true');