import os
from datetime import datetime
from decimal import Decimal, InvalidOperation

from nicegui import app, ui
from peewee import fn
from werkzeug.security import check_password_hash, generate_password_hash

from models import Item, Message, User, create_tables, db

# ── 常量 ─────────────────────────────────────────────
CATEGORY_OPTIONS = ["生活用品", "学习资料", "电子产品", "技能服务"]
TRADE_OPTIONS = ["线下当面", "线上寄送"]
STATUS_LABELS = {"on_sale": "在售", "sold": "已售出", "closed": "已下架"}
STATUS_COLORS = {"on_sale": "positive", "sold": "warning", "closed": "negative"}


# ── 工具函数 ──────────────────────────────────────────
def current_user():
    """从 NiceGUI 会话存储中取出当前登录用户。"""
    uid = app.storage.user.get("user_id")
    if not uid:
        return None
    try:
        return User.get_by_id(uid)
    except User.DoesNotExist:
        return None


def is_logged_in():
    return app.storage.user.get("user_id") is not None


def is_admin():
    return app.storage.user.get("role") == "admin"


def ensure_default_admin():
    """首次运行时创建默认管理员。"""
    if not User.select().where(User.role == "admin").exists():
        User.create(
            username="admin",
            password_hash=generate_password_hash("admin123"),
            role="admin",
            contact="管理员默认联系方式",
        )


def format_price(price):
    if price is None:
        return "面议"
    return f"¥{float(price):.2f}"


# ── 通用页面框架 ──────────────────────────────────────
def page_header():
    """所有页面共用的顶部导航栏。"""
    user = current_user()
    with ui.header().classes("items-center justify-between bg-blue-8 px-6"):
        ui.link("校园二手交易平台", "/").classes(
            "text-white text-xl font-bold no-underline"
        )
        with ui.row().classes("items-center gap-4"):
            ui.link("首页", "/").classes("text-white no-underline")
            if user:
                ui.link("发布商品", "/item/new").classes("text-white no-underline")
                ui.link("我的发布", "/my-items").classes("text-white no-underline")
                if user.role == "admin":
                    ui.link("后台管理", "/admin/items").classes(
                        "text-white no-underline"
                    )
                ui.label(f"你好，{user.username}").classes("text-white")
                ui.button("退出", on_click=do_logout).props("flat color=white size=sm")
            else:
                ui.link("登录", "/login").classes("text-white no-underline")
                ui.link("注册", "/register").classes("text-white no-underline")


def page_footer():
    """所有页面共用的底部。"""
    with ui.footer().classes("bg-grey-3 text-center q-pa-sm"):
        ui.label("校园二手交易平台 · NiceGUI + Peewee").classes("text-grey-7 text-sm")


def do_logout():
    app.storage.user.clear()
    ui.navigate.to("/")


# ══════════════════════════════════════════════════════
#  页面 1：首页 —— 浏览 & 筛选商品
# ══════════════════════════════════════════════════════
@ui.page("/")
def page_index():
    page_header()

    # 简介区域
    with ui.column().classes("w-full items-center q-pt-lg q-pb-md"):
        ui.label('拯救寝室里的"断舍离"').classes("text-h4 text-bold")
        ui.label(
            "面向校园的二手信息发布平台，帮助同学们把闲置物品高效流转起来。"
        ).classes("text-subtitle1 text-grey-7")

    # 筛选栏 — 直接放在 row 里保证水平排列
    with ui.row().classes("w-full items-end gap-4 q-px-lg"):
        keyword = ui.input("关键词搜索", placeholder="如：台灯、教材").classes("w-48")
        category_sel = ui.select(
            ["全部分类"] + CATEGORY_OPTIONS, value="全部分类", label="分类"
        ).classes("w-36")
        status_sel = ui.select(
            {"": "默认（不含已下架）", "on_sale": "在售", "sold": "已售出", "closed": "已下架"},
            value="",
            label="状态",
        ).classes("w-44")
        search_btn = ui.button("筛选", icon="search").props("color=primary")
    container = ui.column().classes("w-full q-px-lg")

    def load_items():
        container.clear()
        query = (
            Item.select(Item, User.username)
            .join(User)
            .order_by(Item.created_at.desc())
        )
        kw = keyword.value.strip() if keyword.value else ""
        if kw:
            query = query.where(
                (Item.title.contains(kw)) | (Item.description.contains(kw))
            )
        cat = category_sel.value
        if cat and cat != "全部分类":
            query = query.where(Item.category == cat)
        st = status_sel.value
        if st:
            query = query.where(Item.status == st)
        else:
            query = query.where(Item.status != "closed")

        items = list(query)
        with container:
            if not items:
                ui.label("暂无符合条件的商品，换个筛选条件试试。").classes(
                    "text-grey-6 q-pa-lg"
                )
                return
            with ui.row().classes("w-full flex-wrap gap-4 q-pa-md items-stretch"):
                for it in items:
                    with ui.card().classes("w-72 cursor-pointer flex column justify-between").on(
                        "click",
                        lambda _, iid=it.id: ui.navigate.to(f"/item/{iid}"),
                    ):
                        with ui.row().classes("items-center justify-between w-full"):
                            ui.label(it.title).classes("text-subtitle1 text-bold")
                            ui.badge(
                                STATUS_LABELS.get(it.status, it.status),
                                color=STATUS_COLORS.get(it.status, "grey"),
                            )
                        ui.label(
                            f"分类：{it.category} | 方式：{it.trade_type} | 发布者：{it.user.username}"
                        ).classes("text-caption text-grey-7")
                        desc = it.description
                        if len(desc) > 70:
                            desc = desc[:70] + "..."
                        ui.label(desc).classes("text-body2")
                        with ui.row().classes("items-center justify-between w-full"):
                            ui.label(format_price(it.price)).classes(
                                "text-bold text-red-7"
                            )
                            ui.button(
                                "查看详情",
                                on_click=lambda _, iid=it.id: ui.navigate.to(
                                    f"/item/{iid}"
                                ),
                            ).props("flat dense color=primary size=sm")

    search_btn.on_click(load_items)
    load_items()

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 2：用户注册
# ══════════════════════════════════════════════════════
@ui.page("/register")
def page_register():
    page_header()

    with ui.card().classes("absolute-center w-96"):
        ui.label("用户注册").classes("text-h5 text-bold q-mb-md")
        username = ui.input("用户名").props("outlined dense").classes("w-full")
        password = ui.input("密码", password=True, password_toggle_button=True).props(
            "outlined dense"
        ).classes("w-full")
        confirm = ui.input(
            "确认密码", password=True, password_toggle_button=True
        ).props("outlined dense").classes("w-full")
        contact = ui.input("联系方式（QQ/微信/手机号）").props("outlined dense").classes("w-full")

        def do_register():
            u = username.value.strip()
            p = password.value
            c = confirm.value
            ct = contact.value.strip()
            if not u or not p:
                ui.notify("用户名和密码不能为空", type="negative")
                return
            if p != c:
                ui.notify("两次输入的密码不一致", type="negative")
                return
            if User.select().where(User.username == u).exists():
                ui.notify("用户名已存在，请更换一个", type="negative")
                return
            User.create(
                username=u,
                password_hash=generate_password_hash(p),
                role="user",
                contact=ct,
            )
            ui.notify("注册成功，请登录", type="positive")
            ui.navigate.to("/login")

        ui.button("注册", on_click=do_register).classes("w-full q-mt-sm")
        with ui.row().classes("justify-center"):
            ui.label("已有账号？")
            ui.link("去登录", "/login")

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 3：用户登录
# ══════════════════════════════════════════════════════
@ui.page("/login")
def page_login():
    page_header()

    with ui.card().classes("absolute-center w-96"):
        ui.label("用户登录").classes("text-h5 text-bold q-mb-md")
        username = ui.input("用户名").props("outlined dense").classes("w-full")
        password = ui.input("密码", password=True, password_toggle_button=True).props(
            "outlined dense"
        ).classes("w-full")

        def do_login():
            u = username.value.strip()
            p = password.value
            try:
                user = User.get(User.username == u)
            except User.DoesNotExist:
                ui.notify("用户名或密码错误", type="negative")
                return
            if not check_password_hash(user.password_hash, p):
                ui.notify("用户名或密码错误", type="negative")
                return
            app.storage.user["user_id"] = user.id
            app.storage.user["role"] = user.role
            app.storage.user["username"] = user.username
            ui.notify(f"欢迎回来，{user.username}！", type="positive")
            ui.navigate.to("/")

        ui.button("登录", on_click=do_login).classes("w-full q-mt-sm")
        with ui.row().classes("justify-center"):
            ui.label("没有账号？")
            ui.link("去注册", "/register")

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 4：发布商品
# ══════════════════════════════════════════════════════
@ui.page("/item/new")
def page_new_item():
    if not is_logged_in():
        ui.navigate.to("/login")
        return

    page_header()

    with ui.card().classes("mx-auto q-mt-lg w-[600px]"):
        ui.label("发布二手信息").classes("text-h5 text-bold q-mb-md")
        title = ui.input("标题").props("outlined dense").classes("w-full")
        category = ui.select(CATEGORY_OPTIONS, label="分类").props(
            "outlined dense"
        ).classes("w-full")
        price = ui.input("价格（可留空表示面议）", placeholder="例如：35 或 99.9").props(
            "outlined dense"
        ).classes("w-full")
        trade_type = ui.select(TRADE_OPTIONS, label="交易方式").props(
            "outlined dense"
        ).classes("w-full")
        contact_input = ui.input(
            "联系方式（可留空，默认用注册时填写的）", placeholder="QQ / 微信 / 手机号"
        ).props("outlined dense").classes("w-full")
        description = (
            ui.textarea("商品描述", placeholder="简单描述成色、购入时间、是否可议价等")
            .props("outlined dense rows=5")
            .classes("w-full")
        )

        def do_publish():
            t = title.value.strip()
            d = description.value.strip()
            if not t or not d:
                ui.notify("标题和描述不能为空", type="negative")
                return
            if not category.value:
                ui.notify("请选择分类", type="negative")
                return
            if not trade_type.value:
                ui.notify("请选择交易方式", type="negative")
                return
            p = None
            if price.value and price.value.strip():
                try:
                    p = Decimal(price.value.strip())
                except InvalidOperation:
                    ui.notify("价格格式不正确，请输入数字", type="negative")
                    return
            ct = contact_input.value.strip()
            if not ct:
                user = current_user()
                ct = user.contact if user and user.contact else "未填写联系方式"
            Item.create(
                title=t,
                description=d,
                category=category.value,
                price=p,
                trade_type=trade_type.value,
                contact=ct,
                status="on_sale",
                created_at=datetime.now(),
                user=app.storage.user["user_id"],
            )
            ui.notify("发布成功！", type="positive")
            ui.navigate.to("/my-items")

        ui.button("确认发布", on_click=do_publish, icon="publish").classes(
            "w-full q-mt-sm"
        )

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 5：商品详情 + 留言
# ══════════════════════════════════════════════════════
@ui.page("/item/{item_id}")
def page_item_detail(item_id: int):
    page_header()

    try:
        item = Item.select(Item, User.username).join(User).where(Item.id == item_id).get()
    except Item.DoesNotExist:
        ui.label("商品不存在或已被删除。").classes("text-h6 text-negative q-pa-lg")
        page_footer()
        return

    user = current_user()
    can_edit = False
    if user:
        can_edit = user.role == "admin" or user.id == item.user_id

    with ui.card().classes("mx-auto q-mt-lg w-[700px]"):
        with ui.row().classes("items-center justify-between w-full"):
            ui.label(item.title).classes("text-h5 text-bold")
            ui.badge(
                STATUS_LABELS.get(item.status, item.status),
                color=STATUS_COLORS.get(item.status, "grey"),
            ).classes("text-sm")

        ui.separator()

        with ui.grid(columns=2).classes("w-full gap-2 q-pa-sm"):
            ui.label("分类：").classes("text-bold")
            ui.label(item.category)
            ui.label("价格：").classes("text-bold")
            ui.label(format_price(item.price)).classes("text-red-7 text-bold")
            ui.label("交易方式：").classes("text-bold")
            ui.label(item.trade_type)
            ui.label("联系方式：").classes("text-bold")
            ui.label(item.contact)
            ui.label("发布者：").classes("text-bold")
            ui.label(item.user.username)
            ui.label("发布时间：").classes("text-bold")
            ui.label(str(item.created_at)[:19])

        ui.separator()
        ui.label("商品描述").classes("text-subtitle1 text-bold")
        ui.label(item.description).classes("q-pa-sm")

        # 状态修改按钮
        if can_edit:
            ui.separator()
            ui.label("修改状态").classes("text-subtitle1 text-bold")
            with ui.row().classes("gap-2"):

                def update_status(new_status):
                    Item.update(status=new_status).where(Item.id == item_id).execute()
                    ui.notify("商品状态已更新", type="positive")
                    ui.navigate.to(f"/item/{item_id}")

                if item.status != "sold":
                    ui.button(
                        "标记为已售出",
                        on_click=lambda: update_status("sold"),
                        icon="check_circle",
                    ).props("color=warning")
                if item.status != "on_sale":
                    ui.button(
                        "恢复为在售",
                        on_click=lambda: update_status("on_sale"),
                        icon="storefront",
                    ).props("color=positive")
                if item.status != "closed":
                    ui.button(
                        "关闭发布",
                        on_click=lambda: update_status("closed"),
                        icon="block",
                    ).props("color=negative")
                else:
                    ui.button(
                        "重新上架",
                        on_click=lambda: update_status("on_sale"),
                        icon="replay",
                    ).props("color=positive")

    # ── 留言区域 ──
    with ui.card().classes("mx-auto q-mt-md w-[700px]"):
        ui.label("商品留言").classes("text-h6 text-bold q-mb-sm")

        msg_container = ui.column().classes("w-full")

        def load_messages():
            msg_container.clear()
            msgs = (
                Message.select(Message, User.username)
                .join(User, on=(Message.sender == User.id))
                .where(Message.item == item_id)
                .order_by(Message.created_at.asc())
            )
            with msg_container:
                if not msgs.count():
                    ui.label("暂无留言").classes("text-grey-6")
                    return
                for m in msgs:
                    with ui.row().classes("items-start gap-2 w-full q-py-xs"):
                        ui.badge(m.sender.username, color="blue").classes("q-mt-xs")
                        with ui.column().classes("gap-0"):
                            ui.label(m.content).classes("text-body2")
                            ui.label(str(m.created_at)[:19]).classes(
                                "text-caption text-grey-6"
                            )

        load_messages()

        if user:
            ui.separator()
            msg_input = ui.input("写留言...", placeholder="输入你的留言内容").props(
                "outlined dense"
            ).classes("w-full")

            def send_msg():
                txt = msg_input.value.strip()
                if not txt:
                    ui.notify("留言内容不能为空", type="negative")
                    return
                Message.create(
                    content=txt,
                    sender=user.id,
                    item=item_id,
                    created_at=datetime.now(),
                )
                msg_input.value = ""
                ui.notify("留言成功", type="positive")
                load_messages()

            ui.button("发送留言", on_click=send_msg, icon="send").props(
                "color=primary dense"
            )
        else:
            ui.label("登录后可以留言").classes("text-grey-6 text-caption")

    # 返回按钮
    with ui.row().classes("mx-auto q-mt-md w-[700px]"):
        ui.button("返回首页", on_click=lambda: ui.navigate.to("/"), icon="home").props(
            "flat color=primary"
        )

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 6：我的发布
# ══════════════════════════════════════════════════════
@ui.page("/my-items")
def page_my_items():
    if not is_logged_in():
        ui.navigate.to("/login")
        return

    page_header()
    uid = app.storage.user["user_id"]

    with ui.column().classes("w-full q-pa-lg"):
        ui.label("我的发布").classes("text-h5 text-bold q-mb-md")

        items = (
            Item.select()
            .where(Item.user == uid)
            .order_by(Item.created_at.desc())
        )

        if not items.count():
            with ui.row().classes("items-center gap-2"):
                ui.label("你还没有发布商品，快去")
                ui.link("发布一个", "/item/new")
                ui.label("吧。")
        else:
            columns = [
                {"name": "title", "label": "标题", "field": "title", "align": "left"},
                {"name": "category", "label": "分类", "field": "category"},
                {"name": "price", "label": "价格", "field": "price"},
                {"name": "status", "label": "状态", "field": "status"},
                {"name": "created_at", "label": "发布时间", "field": "created_at"},
                {"name": "action", "label": "操作", "field": "action"},
            ]
            rows = []
            for it in items:
                rows.append(
                    {
                        "id": it.id,
                        "title": it.title,
                        "category": it.category,
                        "price": format_price(it.price),
                        "status": STATUS_LABELS.get(it.status, it.status),
                        "created_at": str(it.created_at)[:19],
                        "action": "",
                    }
                )

            table = ui.table(columns=columns, rows=rows, row_key="id").classes(
                "w-full"
            )
            table.add_slot(
                "body-cell-action",
                """
                <q-td :props="props">
                    <q-btn flat dense color="primary" label="详情"
                           @click="$parent.$emit('detail', props.row)" />
                </q-td>
                """,
            )
            table.on("detail", lambda e: ui.navigate.to(f"/item/{e.args['id']}"))

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 7：管理员 - 商品管理
# ══════════════════════════════════════════════════════
@ui.page("/admin/items")
def page_admin_items():
    if not is_admin():
        ui.navigate.to("/")
        return

    page_header()

    with ui.column().classes("w-full q-pa-lg"):
        ui.label("管理员后台 - 商品管理").classes("text-h5 text-bold")
        with ui.row().classes("gap-4 q-my-sm"):
            ui.link("商品管理", "/admin/items").classes("text-bold text-primary")
            ui.link("用户管理", "/admin/users")
        ui.label("可删除违规、过期或重复发布的信息。").classes(
            "text-caption text-grey-7 q-mb-md"
        )

        items_container = ui.column().classes("w-full")

        def load_admin_items():
            items_container.clear()
            items = (
                Item.select(Item, User.username)
                .join(User)
                .order_by(Item.created_at.desc())
            )
            rows = []
            for it in items:
                rows.append(
                    {
                        "id": it.id,
                        "title": it.title,
                        "username": it.user.username,
                        "category": it.category,
                        "status": STATUS_LABELS.get(it.status, it.status),
                        "created_at": str(it.created_at)[:19],
                    }
                )
            columns = [
                {"name": "id", "label": "ID", "field": "id"},
                {"name": "title", "label": "标题", "field": "title", "align": "left"},
                {"name": "username", "label": "发布者", "field": "username"},
                {"name": "category", "label": "分类", "field": "category"},
                {"name": "status", "label": "状态", "field": "status"},
                {"name": "created_at", "label": "发布时间", "field": "created_at"},
                {"name": "action", "label": "操作", "field": "action"},
            ]

            with items_container:
                if not rows:
                    ui.label("暂无商品数据。").classes("text-grey-6")
                    return
                table = ui.table(columns=columns, rows=rows, row_key="id").classes(
                    "w-full"
                )
                table.add_slot(
                    "body-cell-title",
                    """
                    <q-td :props="props">
                        <q-btn flat dense color="primary" :label="props.row.title"
                               @click="$parent.$emit('view', props.row)" />
                    </q-td>
                    """,
                )
                table.add_slot(
                    "body-cell-action",
                    """
                    <q-td :props="props">
                        <q-btn flat dense color="negative" label="删除"
                               @click="$parent.$emit('delete', props.row)" />
                    </q-td>
                    """,
                )
                table.on(
                    "view", lambda e: ui.navigate.to(f"/item/{e.args['id']}")
                )

                async def handle_delete(e):
                    item_id = e.args["id"]
                    with ui.dialog() as dialog, ui.card():
                        ui.label("确认删除该商品吗？")
                        with ui.row().classes("justify-end w-full"):
                            ui.button("取消", on_click=dialog.close).props("flat")

                            def confirm_del():
                                Message.delete().where(
                                    Message.item == item_id
                                ).execute()
                                Item.delete().where(Item.id == item_id).execute()
                                dialog.close()
                                ui.notify("商品已删除", type="positive")
                                load_admin_items()

                            ui.button("确认删除", on_click=confirm_del).props(
                                "color=negative"
                            )
                    dialog.open()

                table.on("delete", handle_delete)

        load_admin_items()

    page_footer()


# ══════════════════════════════════════════════════════
#  页面 8：管理员 - 用户管理
# ══════════════════════════════════════════════════════
@ui.page("/admin/users")
def page_admin_users():
    if not is_admin():
        ui.navigate.to("/")
        return

    page_header()

    with ui.column().classes("w-full q-pa-lg"):
        ui.label("管理员后台 - 用户管理").classes("text-h5 text-bold")
        with ui.row().classes("gap-4 q-my-sm"):
            ui.link("商品管理", "/admin/items")
            ui.link("用户管理", "/admin/users").classes("text-bold text-primary")
        ui.label("可查看用户信息，删除违规账号（会同步删除其发布的商品和留言）。").classes(
            "text-caption text-grey-7 q-mb-md"
        )

        users_container = ui.column().classes("w-full")

        def load_admin_users():
            users_container.clear()
            users = User.select().order_by(User.role.desc(), User.id.asc())
            rows = []
            for u in users:
                count = Item.select().where(Item.user == u.id).count()
                rows.append(
                    {
                        "id": u.id,
                        "username": u.username,
                        "role": "管理员" if u.role == "admin" else "普通用户",
                        "raw_role": u.role,
                        "contact": u.contact if u.contact else "未填写",
                        "item_count": count,
                    }
                )
            columns = [
                {"name": "id", "label": "ID", "field": "id"},
                {
                    "name": "username",
                    "label": "用户名",
                    "field": "username",
                    "align": "left",
                },
                {"name": "role", "label": "角色", "field": "role"},
                {"name": "contact", "label": "联系方式", "field": "contact"},
                {"name": "item_count", "label": "发布数量", "field": "item_count"},
                {"name": "action", "label": "操作", "field": "action"},
            ]
            with users_container:
                if not rows:
                    ui.label("暂无用户数据。").classes("text-grey-6")
                    return
                table = ui.table(columns=columns, rows=rows, row_key="id").classes(
                    "w-full"
                )
                table.add_slot(
                    "body-cell-action",
                    """
                    <q-td :props="props">
                        <q-btn v-if="props.row.raw_role !== 'admin'"
                               flat dense color="negative" label="删除用户"
                               @click="$parent.$emit('deleteUser', props.row)" />
                        <span v-else class="text-grey">管理员不可删</span>
                    </q-td>
                    """,
                )

                async def handle_delete_user(e):
                    uid = e.args["id"]
                    with ui.dialog() as dialog, ui.card():
                        ui.label("确认删除该用户及其商品吗？")
                        with ui.row().classes("justify-end w-full"):
                            ui.button("取消", on_click=dialog.close).props("flat")

                            def confirm_del():
                                Message.delete().where(
                                    Message.sender == uid
                                ).execute()
                                Item.delete().where(Item.user == uid).execute()
                                User.delete().where(User.id == uid).execute()
                                dialog.close()
                                ui.notify("用户及其数据已删除", type="positive")
                                load_admin_users()

                            ui.button("确认删除", on_click=confirm_del).props(
                                "color=negative"
                            )
                    dialog.open()

                table.on("deleteUser", handle_delete_user)

        load_admin_users()

    page_footer()


# ── 初始化数据库与管理员 ──────────────────────────────
create_tables()
ensure_default_admin()

# ── 启动 NiceGUI ──────────────────────────────────────
ui.run(
    title="校园二手交易平台",
    port=8080,
    storage_secret="student-second-hand-platform",
    language="zh-CN",
)
