# 借还登记器 · 课堂演示件（用于打包）
#
# 用法：直接运行可以用，打包成 exe 之后同样可以用。
#       数据存在同目录下的 items.db，第一次运行会自动建库。

import sqlite3
import sys
import tkinter as tk
from tkinter import messagebox
from datetime import datetime
from pathlib import Path


# ==================== 打包后仍然找得到数据的关键 ====================


def app_dir():
    """程序所在目录。
    直接运行 .py 时，返回 .py 所在的文件夹；
    打包成 exe 之后，返回 exe 所在的文件夹。
    不要用 __file__，打包后它指向的是临时解压目录。"""
    if getattr(sys, 'frozen', False):
        return Path(sys.executable).parent
    return Path(__file__).parent


DB = app_dir() / 'items.db'


# ==================== 逻辑区 ====================


def init_db():
    """第一次运行时自动建表，之后每次运行都不会重复建"""
    conn = sqlite3.connect(DB)
    conn.execute('''CREATE TABLE IF NOT EXISTS records (
        id        INTEGER PRIMARY KEY AUTOINCREMENT,
        item      TEXT    NOT NULL,
        borrower  TEXT    NOT NULL,
        borrow_at TEXT    NOT NULL,
        return_at TEXT)''')
    conn.commit()
    conn.close()


def add_record(item, borrower):
    """登记借出。同一件物资未归还时不允许重复借出"""
    conn = sqlite3.connect(DB)
    busy = conn.execute(
        'SELECT borrower FROM records WHERE item = ? AND return_at IS NULL',
        (item,)).fetchone()
    if busy:
        conn.close()
        return '「' + item + '」还在 ' + busy[0] + ' 手上，不能重复借出。'
    conn.execute(
        'INSERT INTO records (item, borrower, borrow_at) VALUES (?, ?, ?)',
        (item, borrower, datetime.now().strftime('%Y-%m-%d %H:%M')))
    conn.commit()
    conn.close()
    return '已登记：' + borrower + ' 借走「' + item + '」'


def close_record(item):
    """登记归还"""
    conn = sqlite3.connect(DB)
    cur = conn.execute(
        'UPDATE records SET return_at = ? WHERE item = ? AND return_at IS NULL',
        (datetime.now().strftime('%Y-%m-%d %H:%M'), item))
    conn.commit()
    conn.close()
    if cur.rowcount == 0:
        return '「' + item + '」没有未归还的记录。'
    return '已登记归还：「' + item + '」'


def unreturned():
    """列出所有未归还的记录"""
    conn = sqlite3.connect(DB)
    rows = conn.execute(
        'SELECT item, borrower, borrow_at FROM records '
        'WHERE return_at IS NULL ORDER BY borrow_at').fetchall()
    conn.close()
    return rows


# ==================== 窗口外壳 ====================


def refresh():
    """把未归还清单重新刷到文本框里"""
    box.delete('1.0', tk.END)
    rows = unreturned()
    for item, borrower, at in rows:
        box.insert(tk.END, item + '　—　' + borrower + '　—　' + at + '\n')
    status.config(text='未归还 ' + str(len(rows)) + ' 件　｜　数据文件：' + str(DB))


def on_borrow():
    item = item_entry.get().strip()
    borrower = who_entry.get().strip()
    if not item or not borrower:
        messagebox.showwarning('还差一项', '物资名称与借用人都要填。')
        return
    try:
        messagebox.showinfo('登记结果', add_record(item, borrower))
    except Exception as error:
        messagebox.showerror('出错了', '写入数据时出了问题：\n\n' + str(error))
        return
    refresh()


def on_return():
    item = item_entry.get().strip()
    if not item:
        messagebox.showwarning('还差一项', '请先填写要归还的物资名称。')
        return
    try:
        messagebox.showinfo('登记结果', close_record(item))
    except Exception as error:
        messagebox.showerror('出错了', '写入数据时出了问题：\n\n' + str(error))
        return
    refresh()


init_db()

root = tk.Tk()
root.title('社团物资借还登记器')
root.geometry('560x380')
root.minsize(460, 300)

top = tk.Frame(root, padx=12, pady=10)
top.pack(fill='x')
tk.Label(top, text='物资：').pack(side='left')
item_entry = tk.Entry(top, width=14)
item_entry.pack(side='left', padx=(0, 10))
tk.Label(top, text='借用人：').pack(side='left')
who_entry = tk.Entry(top, width=10)
who_entry.pack(side='left', padx=(0, 12))
tk.Button(top, text='登记借出', command=on_borrow).pack(side='left')
tk.Button(top, text='登记归还', command=on_return).pack(side='left', padx=8)

tk.Label(root, text='未归还清单', anchor='w', padx=12).pack(fill='x')
box = tk.Text(root, height=12)
box.pack(fill='both', expand=True, padx=12, pady=(0, 8))

status = tk.Label(root, text='', anchor='w', padx=12, pady=6, relief='sunken')
status.pack(fill='x', side='bottom')

refresh()
root.mainloop()
