import uuid

from fastapi import APIRouter, File, Form, Query, UploadFile

from app.api.deps import AdminDep, ClientDep, PageDep, SessionDep, UserDep
from app.api.serializers import dump, dump_list
from app.core.response import paginated, success
from app.schemas import (
    CouponCreate,
    CouponOut,
    CouponUpdate,
    LogOut,
    MenuUpdate,
    MessagesUpdate,
    ReferralOut,
    SettingsUpdate,
    SupportReply,
    SupportTicketIn,
    SupportTicketOut,
)
from app.services import (
    CouponService,
    DashboardService,
    LogService,
    MessageService,
    ReferralService,
    SettingsService,
    SupportService,
    UploadService,
)

router = APIRouter(tags=["misc"])


# -- settings & bot configuration -----------------------------------
@router.get("/settings")
async def public_settings(session: SessionDep, _: ClientDep) -> dict:
    return success(await SettingsService(session).public())


@router.get("/bot/config")
async def bot_config(session: SessionDep, _: ClientDep) -> dict:
    """Everything the bot caches: texts, menu and public settings."""
    messages = MessageService(session)
    return success(
        {
            "messages": await messages.all(),
            "menu": await messages.menu(),
            "settings": await SettingsService(session).public(),
        }
    )


@router.get("/admin/settings")
async def admin_settings(session: SessionDep, _: AdminDep) -> dict:
    service = SettingsService(session)
    return success({"values": await service.all(refresh=True)})


@router.put("/admin/settings")
async def update_settings(payload: SettingsUpdate, session: SessionDep, _: AdminDep) -> dict:
    service = SettingsService(session)
    await service.set_many(payload.values)
    return success({"values": await service.all(refresh=True)}, "settings_updated")


@router.get("/admin/messages")
async def admin_messages(session: SessionDep, _: AdminDep) -> dict:
    service = MessageService(session)
    return success(
        {
            "defaults": service.defaults(),
            "overrides": await service.overrides(),
            "messages": await service.all(),
        }
    )


@router.put("/admin/messages")
async def update_messages(payload: MessagesUpdate, session: SessionDep, _: AdminDep) -> dict:
    service = MessageService(session)
    await service.update(payload.values)
    return success({"messages": await service.all()}, "messages_updated")


@router.get("/admin/menu")
async def admin_menu(session: SessionDep, _: AdminDep) -> dict:
    return success(await MessageService(session).menu_all())


@router.put("/admin/menu")
async def update_menu(payload: MenuUpdate, session: SessionDep, _: AdminDep) -> dict:
    items = await MessageService(session).update_menu(payload.items)
    return success(items, "menu_updated")


# -- coupons --------------------------------------------------------
@router.get("/admin/coupons")
async def list_coupons(session: SessionDep, _: AdminDep, page_params: PageDep) -> dict:
    items, total = await CouponService(session).search(
        page_params.page, page_params.size, page_params.search
    )
    return success(paginated(dump_list(CouponOut, items), total, page_params.page, page_params.size))


@router.post("/admin/coupons")
async def create_coupon(payload: CouponCreate, session: SessionDep, _: AdminDep) -> dict:
    coupon = await CouponService(session).create(**payload.model_dump())
    return success(dump(CouponOut, coupon), "created")


@router.put("/admin/coupons/{coupon_id}")
async def update_coupon(
    coupon_id: uuid.UUID, payload: CouponUpdate, session: SessionDep, _: AdminDep
) -> dict:
    coupon = await CouponService(session).update(
        coupon_id, **payload.model_dump(exclude_unset=True)
    )
    return success(dump(CouponOut, coupon), "updated")


@router.delete("/admin/coupons/{coupon_id}")
async def delete_coupon(coupon_id: uuid.UUID, session: SessionDep, _: AdminDep) -> dict:
    await CouponService(session).delete(coupon_id)
    return success(None, "deleted")


# -- referral -------------------------------------------------------
@router.get("/referral")
async def referral_info(user: UserDep, session: SessionDep) -> dict:
    service = ReferralService(session)
    stats = await service.statistics(user)
    return success({**stats, "referrals": dump_list(ReferralOut, await service.list_for_user(user.id))})


@router.get("/admin/referrals")
async def admin_referrals(
    session: SessionDep, _: AdminDep, page_params: PageDep, status: str | None = Query(default=None)
) -> dict:
    items, total = await ReferralService(session).search(
        page_params.page, page_params.size, status=status
    )
    return success(
        paginated(dump_list(ReferralOut, items), total, page_params.page, page_params.size)
    )


# -- support --------------------------------------------------------
@router.post("/support")
async def create_ticket(payload: SupportTicketIn, user: UserDep, session: SessionDep) -> dict:
    ticket = await SupportService(session).create_ticket(
        user, payload.message, payload.subject, payload.attachment
    )
    return success(dump(SupportTicketOut, ticket), "ticket_created")


@router.get("/support")
async def my_tickets(user: UserDep, session: SessionDep, page_params: PageDep) -> dict:
    items, total = await SupportService(session).search(
        page_params.page, page_params.size, user_id=user.id
    )
    return success(
        paginated(dump_list(SupportTicketOut, items), total, page_params.page, page_params.size)
    )


@router.get("/admin/support")
async def admin_tickets(
    session: SessionDep, _: AdminDep, page_params: PageDep, status: str | None = Query(default=None)
) -> dict:
    items, total = await SupportService(session).search(
        page_params.page, page_params.size, status=status
    )
    return success(
        paginated(dump_list(SupportTicketOut, items), total, page_params.page, page_params.size)
    )


@router.post("/admin/support/{ticket_id}/reply")
async def reply_ticket(
    ticket_id: uuid.UUID, payload: SupportReply, session: SessionDep, _: AdminDep
) -> dict:
    ticket = await SupportService(session).reply(ticket_id, payload.message)
    return success(dump(SupportTicketOut, ticket), "ticket_answered")


@router.put("/admin/support/{ticket_id}/close")
async def close_ticket(ticket_id: uuid.UUID, session: SessionDep, _: AdminDep) -> dict:
    ticket = await SupportService(session).close(ticket_id)
    return success(dump(SupportTicketOut, ticket), "ticket_closed")


# -- logs & dashboard -----------------------------------------------
@router.get("/admin/logs")
async def list_logs(
    session: SessionDep,
    _: AdminDep,
    page_params: PageDep,
    type: str | None = Query(default=None),
    event: str | None = Query(default=None),
) -> dict:
    items, total = await LogService(session).search(
        page_params.page, page_params.size, type=type, event=event, search=page_params.search
    )
    return success(paginated(dump_list(LogOut, items), total, page_params.page, page_params.size))


@router.get("/admin/dashboard")
async def dashboard(session: SessionDep, _: AdminDep) -> dict:
    from app.schemas import OrderOut, PaymentOut

    service = DashboardService(session)
    return success(
        {
            "summary": await service.summary(),
            "chart": await service.sales_chart(),
            "latest_orders": dump_list(OrderOut, await service.latest_orders()),
            "latest_payments": dump_list(PaymentOut, await service.latest_payments()),
        }
    )


# -- uploads --------------------------------------------------------
@router.post("/admin/upload")
async def upload_file(
    _: AdminDep, file: UploadFile = File(...), folder: str = Form(default="products")
) -> dict:
    return success(await UploadService().save_image(file, folder), "uploaded")


@router.get("/admin/media")
async def list_media(_: AdminDep, folder: str = Query(default="products")) -> dict:
    return success(UploadService().list_files(folder))


@router.delete("/admin/media")
async def delete_media(_: AdminDep, path: str = Query(...)) -> dict:
    deleted = UploadService().delete(path)
    return success({"deleted": deleted}, "deleted" if deleted else "not_found")
