from __future__ import annotations

import typer

from flow_xhs.contracts.command_inputs import NoteSearchInput, UserSearchInput
from flow_xhs.services.note_search import execute_note_search
from flow_xhs.services.user_search import execute_user_search
from flow_xhs.cli.context import CliContext
from flow_xhs.cli.runtime import run_async_command
from flow_xhs.cli.utils import all_option_params_are_default, load_json_input, pick_cli_or_input

app = typer.Typer(help="统一搜索入口（笔记/用户）", no_args_is_help=True)
note_app = typer.Typer(help="搜索笔记", no_args_is_help=False)
user_app = typer.Typer(help="搜索用户", no_args_is_help=False)


@note_app.callback(invoke_without_command=True)
def search_note(
    ctx: typer.Context,
    keyword: str | None = typer.Option(None, "--keyword", help="关键词（1..n）；可由 --input 提供"),
    size: int | None = typer.Option(20, "--size", help="返回数量（1..100）"),
    sort_by: str | None = typer.Option(
        None,
        "--sort-by",
        help="排序：comprehensive|latest|most_liked|most_commented|most_favorited（支持中文别名）",
    ),
    note_type: str | None = typer.Option(None, "--note-type", help="类型：all|video|image_text（支持中文别名）"),
    publish_time: str | None = typer.Option(None, "--publish-time", help="发布时间：all|day|week|half_year（支持中文别名）"),
    search_scope: str | None = typer.Option(None, "--search-scope", help="搜索范围：all|viewed|unviewed|following（支持中文别名）"),
    location: str | None = typer.Option(None, "--location", help="位置：all|local|nearby（支持中文别名）"),
    account: str | None = typer.Option(None, "--account", help="账号唯一标识（user_no）"),
    input_file: str | None = typer.Option(
        None,
        "--input",
        help="JSON 输入文件路径或 '-'（stdin），字段示例：keyword,size,sort_by,note_type,publish_time,search_scope,location,account_uid",
    ),
):
    """搜索笔记列表。"""
    if all_option_params_are_default(ctx=ctx):
        typer.echo(ctx.get_help())
        raise typer.Exit(code=0)

    cli_ctx: CliContext = ctx.obj
    payload = load_json_input(input_file)
    account_uid = pick_cli_or_input(
        ctx=ctx,
        param_name="account",
        cli_value=account,
        payload=payload,
        payload_key="account_uid",
    )

    async def _run():
        validated = NoteSearchInput(
            keyword=pick_cli_or_input(
                ctx=ctx,
                param_name="keyword",
                cli_value=keyword,
                payload=payload,
                payload_key="keyword",
            ),
            size=pick_cli_or_input(
                ctx=ctx,
                param_name="size",
                cli_value=size,
                payload=payload,
                payload_key="size",
            ),
            sort_by=pick_cli_or_input(
                ctx=ctx,
                param_name="sort_by",
                cli_value=sort_by,
                payload=payload,
                payload_key="sort_by",
            ),
            note_type=pick_cli_or_input(
                ctx=ctx,
                param_name="note_type",
                cli_value=note_type,
                payload=payload,
                payload_key="note_type",
            ),
            publish_time=pick_cli_or_input(
                ctx=ctx,
                param_name="publish_time",
                cli_value=publish_time,
                payload=payload,
                payload_key="publish_time",
            ),
            search_scope=pick_cli_or_input(
                ctx=ctx,
                param_name="search_scope",
                cli_value=search_scope,
                payload=payload,
                payload_key="search_scope",
            ),
            location=pick_cli_or_input(
                ctx=ctx,
                param_name="location",
                cli_value=location,
                payload=payload,
                payload_key="location",
            ),
            account_uid=account_uid,
        )
        return await execute_note_search(
            keyword=validated.keyword,
            size=validated.size,
            sort_by=validated.sort_by,
            note_type=validated.note_type,
            publish_time=validated.publish_time,
            search_scope=validated.search_scope,
            location=validated.location,
            account_uid=validated.account_uid,
        )

    run_async_command(
        ctx=cli_ctx,
        command="note.search",
        func=_run,
        account_uid=account_uid,
    )


@user_app.callback(invoke_without_command=True)
def search_user(
    ctx: typer.Context,
    keyword: str | None = typer.Option(None, "--keyword", help="关键词（1..n）；可由 --input 提供"),
    size: int | None = typer.Option(20, "--size", help="返回数量（1..100）"),
    account: str | None = typer.Option(None, "--account", help="账号唯一标识（user_no）"),
    input_file: str | None = typer.Option(
        None,
        "--input",
        help="JSON 输入文件路径或 '-'（stdin），字段示例：keyword,size,account_uid",
    ),
):
    """搜索用户列表。"""
    if all_option_params_are_default(ctx=ctx):
        typer.echo(ctx.get_help())
        raise typer.Exit(code=0)

    cli_ctx: CliContext = ctx.obj
    payload = load_json_input(input_file)
    account_uid = pick_cli_or_input(
        ctx=ctx,
        param_name="account",
        cli_value=account,
        payload=payload,
        payload_key="account_uid",
    )

    async def _run():
        validated = UserSearchInput(
            keyword=pick_cli_or_input(
                ctx=ctx,
                param_name="keyword",
                cli_value=keyword,
                payload=payload,
                payload_key="keyword",
            ),
            size=pick_cli_or_input(
                ctx=ctx,
                param_name="size",
                cli_value=size,
                payload=payload,
                payload_key="size",
            ),
            account_uid=account_uid,
        )
        return await execute_user_search(
            keyword=validated.keyword,
            size=validated.size,
            account_uid=validated.account_uid,
        )

    run_async_command(
        ctx=cli_ctx,
        command="user.search",
        func=_run,
        account_uid=account_uid,
    )


app.add_typer(note_app, name="note")
app.add_typer(user_app, name="user")
