"""
資料庫初始化(Seed)腳本。

執行時機:Docker 容器啟動時自動跑(見 Dockerfile CMD)。
功能:確保資料庫裡至少有一個 owner 帳號,讓使用者第一次啟動可以直接登入。

行為:
  1. 連到資料庫
  2. 看 SEED_OWNER_EMAIL 是否已存在
     - 不存在 → 建立 owner
     - 已存在 → 什麼都不做(避免覆蓋使用者後來改的密碼)
  3. 結束

可獨立執行:`python -m app.core.seed`
"""

import asyncio
import logging

from sqlalchemy import select

from app.config import settings
from app.core.security import hash_password
from app.database import AsyncSessionLocal
from app.models.channel import Channel, ChannelMember
from app.models.user import User


# 階段 3e:單一團隊頻道(取代原本 6 個分類頻道)。
# 設計轉向:不靠人腦分頻道,改靠 Coba 自動 tag 標記。所有對話進同一條 thread。
DEFAULT_CHANNELS = [
    {
        "name": "團隊對話",
        "icon": "💬",
        "description": "全公司一起的對話空間。任何事丟進來,庫柏會自動分類。",
        "sort_order": 10,
    },
]


logger = logging.getLogger("coba.seed")
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(message)s")


async def seed_first_owner() -> None:
    """確保 SEED_OWNER_EMAIL 對應的 owner 帳號存在。"""
    async with AsyncSessionLocal() as db:
        # 檢查是否已有同 email 的使用者
        stmt = select(User).where(User.email == settings.SEED_OWNER_EMAIL.lower())
        result = await db.execute(stmt)
        existing = result.scalar_one_or_none()

        if existing is not None:
            logger.info(
                "Owner 帳號已存在,跳過 seed:%s (role=%s)",
                existing.email,
                existing.role,
            )
            return

        owner = User(
            email=settings.SEED_OWNER_EMAIL.lower(),
            password_hash=hash_password(settings.SEED_OWNER_PASSWORD),
            display_name=settings.SEED_OWNER_DISPLAY_NAME,
            role="owner",
            is_active=True,
        )
        db.add(owner)
        await db.commit()
        logger.info(
            "已建立第一個 owner:%s (display_name=%s)",
            owner.email,
            owner.display_name,
        )


async def _consolidate_to_single_channel(db) -> None:
    """階段 3e 一次性遷移:把舊的 6 個分類頻道整併成單一「團隊對話」頻道。

    流程:
      1. 找出所有 is_default=True 但「不是團隊對話」的舊頻道
      2. 找(或建立)「團隊對話」keeper 頻道
      3. 把舊頻道的訊息全部搬到 keeper
      4. 軟刪除舊頻道(deleted_at=now)
    冪等:沒有舊頻道就什麼都不做。
    """
    from datetime import datetime, timezone
    from app.models.channel import Channel, Message

    # 找出舊的多分類預設頻道
    old_stmt = select(Channel).where(
        Channel.is_default.is_(True),
        Channel.deleted_at.is_(None),
        Channel.name.in_(["公告", "靈感與分享", "求助", "會議紀錄", "庫柏動態", "閒聊"]),
    )
    old_channels = list((await db.execute(old_stmt)).scalars().all())
    if not old_channels:
        return

    # 建立 / 取得 keeper(團隊對話)
    keeper_stmt = select(Channel).where(Channel.name == "團隊對話", Channel.deleted_at.is_(None))
    keeper = (await db.execute(keeper_stmt)).scalar_one_or_none()
    if keeper is None:
        keeper = Channel(
            name="團隊對話",
            icon="💬",
            description="全公司一起的對話空間。任何事丟進來,庫柏會自動分類。",
            channel_type="public",
            is_default=True,
            sort_order=10,
        )
        db.add(keeper)
        await db.flush()

    # 把每個舊頻道的訊息搬到 keeper,然後軟刪除舊頻道
    from sqlalchemy import update as sql_update
    moved_total = 0
    for ch in old_channels:
        result = await db.execute(
            sql_update(Message)
            .where(Message.channel_id == ch.id, Message.deleted_at.is_(None))
            .values(channel_id=keeper.id)
        )
        moved_total += result.rowcount or 0
        ch.deleted_at = datetime.now(timezone.utc)
    await db.commit()
    logger.info("已合併 %d 個舊頻道,搬移 %d 則訊息到「團隊對話」", len(old_channels), moved_total)


async def seed_default_channels() -> None:
    """確保預設頻道存在,並把所有使用者自動加為成員。

    階段 3e 變更:
      - 從原本的 6 個分類頻道改為單一「團隊對話」
      - 啟動時自動把舊頻道訊息合併過來
      - Coba 用 tag 取代頻道分類
    冪等。
    """
    async with AsyncSessionLocal() as db:
        # 0. 階段 3e 一次性遷移:把舊多頻道合併成單一「團隊對話」
        await _consolidate_to_single_channel(db)

        # 1. 抓所有現存頻道名稱
        existing = (await db.execute(select(Channel).where(Channel.deleted_at.is_(None)))).scalars().all()
        existing_names = {ch.name for ch in existing}

        # 2. 補建沒有的預設頻道
        created_count = 0
        for spec in DEFAULT_CHANNELS:
            if spec["name"] in existing_names:
                continue
            db.add(Channel(
                name=spec["name"],
                icon=spec["icon"],
                description=spec["description"],
                channel_type="public",
                is_default=True,
                sort_order=spec["sort_order"],
            ))
            created_count += 1
        if created_count:
            await db.commit()
            logger.info("已建立 %d 個預設頻道", created_count)

        # 3. 把所有使用者加入所有 public 頻道(若還沒在裡面)
        users = (await db.execute(
            select(User).where(User.deleted_at.is_(None), User.is_active.is_(True))
        )).scalars().all()
        public_channels = (await db.execute(
            select(Channel).where(
                Channel.channel_type == "public",
                Channel.deleted_at.is_(None),
            )
        )).scalars().all()

        member_added = 0
        for user in users:
            for ch in public_channels:
                # 檢查是否已是成員
                existing_member = (await db.execute(
                    select(ChannelMember).where(
                        ChannelMember.channel_id == ch.id,
                        ChannelMember.user_id == user.id,
                    )
                )).scalar_one_or_none()
                if existing_member is None:
                    db.add(ChannelMember(channel_id=ch.id, user_id=user.id))
                    member_added += 1
        if member_added:
            await db.commit()
            logger.info("已補上 %d 筆 channel_member 關聯", member_added)


async def seed_coba_welcome() -> None:
    """在「公告」頻道發一則庫柏的歡迎訊息(只發一次,冪等)。"""
    from app.models.channel import Channel, Message  # 避免 circular import

    async with AsyncSessionLocal() as db:
        announce = (await db.execute(
            select(Channel).where(Channel.name == "公告", Channel.is_default.is_(True))
        )).scalar_one_or_none()
        if announce is None:
            return

        # 只在公告頻道完全沒訊息時才發歡迎詞
        existing = (await db.execute(
            select(Message).where(Message.channel_id == announce.id).limit(1)
        )).scalars().first()
        if existing is not None:
            return

        welcome = Message(
            channel_id=announce.id,
            user_id=None,   # NULL = 庫柏發的
            content=(
                "嗨,我是庫柏(Cooper)——「山水話菁英團隊」的 AI 同事。\n"
                "我駐紮在這個「行程規畫系統」裡,陪大家管行程、會議、知識與對話。\n\n"
                "我會默默讀群組裡的訊息,在你 @ 我時回應。\n"
                "我也會每天 9:00 產生簡報、會議錄音轉摘要、自動關聯過去討論。\n\n"
                "把我當成「會記得每個人的特助級同事」就對了。"
            ),
            message_type="text",
        )
        db.add(welcome)
        await db.commit()
        logger.info("已 seed 庫柏歡迎訊息")


async def seed_all() -> None:
    """串連所有 seed 任務。"""
    await seed_first_owner()
    await seed_default_channels()
    await seed_coba_welcome()


def main() -> None:
    asyncio.run(seed_all())


if __name__ == "__main__":
    main()
