from __future__ import annotations

from collections.abc import Mapping

from ..agent_tool_core import AgentTool, ToolHandler
from ._builder import resolve_handler


def build_data_agent_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
    """构建数据 Agent 专用工具声明。

    这里仅保存工具名称、描述和 JSON Schema，具体执行逻辑由调用方传入的 handler 提供。
    这样新增数据 Agent 工具时，可以优先在本文件补充声明，再在实现模块中补充 handler。
    """
    return [
        AgentTool(
            name='data_agent_prepare_generation_goal',
            description=(
                'Create a pending data-agent generation goal from source evidence or user rules. '
                'Use this before data_agent_prepare_generation_plan; show the returned goal to the user and wait for confirmation.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'dataset_label': {'type': 'string'},
                    'goal_summary': {'type': 'string'},
                    'target': {
                        'type': 'string',
                        'description': 'Single full target expression, e.g. Agent(tag="餐饮服务") or a function call. For multi-target boundary tasks, use target_definitions.',
                    },
                    'target_definitions': {
                        'type': 'array',
                        'items': {
                            'type': 'object',
                            'properties': {
                                'name': {'type': 'string'},
                                'target': {
                                    'type': 'string',
                                    'description': 'Full target expression, e.g. Agent(tag="餐饮服务"); do not shorten to a display name.',
                                },
                                'rule': {'type': 'string'},
                            },
                            'required': ['target'],
                        },
                    },
                    'plan_hint': {
                        'type': 'string',
                        'description': (
                            'Optional plain-language hint for the later plan, such as '
                            '"建议先生成 50 条单轮，输出到 tasks/.../records.jsonl". '
                            'Structured total_count, turn_mix, and output_path belong to data_agent_prepare_generation_plan.'
                        ),
                    },
                    'coverage': {'type': 'string'},
                    'exclusions': {'type': 'string'},
                    'open_questions': {
                        'type': 'array',
                        'items': {'type': 'string'},
                    },
                    'source_refs': {
                        'type': 'array',
                        'items': {'type': 'string'},
                    },
                    'notes': {'type': 'string'},
                },
                'required': ['dataset_label', 'goal_summary', 'coverage', 'exclusions'],
            },
            handler=resolve_handler(handlers, 'data_agent_prepare_generation_goal', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_confirm_generation_goal',
            description=(
                'Mark a pending data-agent generation goal as confirmed after the user explicitly approves it. '
                'The returned confirmed_goal_id is required by data_agent_prepare_generation_plan.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'goal_id': {'type': 'string'},
                    'confirmation': {
                        'type': 'string',
                        'description': 'The user approval text, such as 确认, 开始生成, or approve.',
                    },
                    'reviewed_revision': {
                        'type': 'integer',
                        'description': 'The goal revision shown to the user before confirmation.',
                    },
                },
                'required': ['goal_id', 'confirmation'],
            },
            handler=resolve_handler(handlers, 'data_agent_confirm_generation_goal', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_prepare_generation_plan',
            description=(
                'Create a pending data-agent generation plan. Use this before generating dataset draft text; '
                'requires confirmed_goal_id from data_agent_confirm_generation_goal; show the returned plan to the user and wait for confirmation.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'confirmed_goal_id': {
                        'type': 'string',
                        'description': 'Returned by data_agent_confirm_generation_goal after the user reviews a separate generation goal. Omit only when direct_review is true.',
                    },
                    'direct_review': {
                        'type': 'boolean',
                        'description': (
                            'Set true for simple hand-written rules where the user already supplied target labels '
                            'and wants generation; this creates one combined goal+plan review instead of a separate goal review.'
                        ),
                    },
                    'dataset_label': {'type': 'string'},
                    'target': {
                        'type': 'string',
                        'description': 'Single full target expression. For multi-target boundary tasks, omit this and fill target_definitions.',
                    },
                    'target_definitions': {
                        'type': 'array',
                        'description': 'Optional target labels for multi-class boundary data.',
                        'items': {
                            'type': 'object',
                            'properties': {
                                'name': {'type': 'string'},
                                'target': {
                                    'type': 'string',
                                    'description': 'Full target expression inherited from the confirmed goal, e.g. Agent(tag="餐饮服务").',
                                },
                                'rule': {'type': 'string'},
                            },
                            'required': ['target'],
                        },
                    },
                    'total_count': {'type': 'integer', 'minimum': 1},
                    'turn_mix': {'type': 'string', 'description': 'Single-turn and multi-turn count or ratio.'},
                    'coverage': {'type': 'string', 'description': 'Query types, intent boundaries, or error types to cover.'},
                    'exclusions': {'type': 'string', 'description': 'Negative examples or boundaries to avoid.'},
                    'output_path': {
                        'type': 'string',
                        'description': (
                            'Requested records path. The runtime normalizes canonical records to the current '
                            'session output/records.jsonl; use output/records.jsonl and do not add dataset '
                            'subdirectories or random names.'
                        ),
                    },
                    'notes': {'type': 'string'},
                },
                'required': [
                    'dataset_label',
                    'total_count',
                    'turn_mix',
                    'coverage',
                    'exclusions',
                    'output_path',
                ],
            },
            handler=resolve_handler(handlers, 'data_agent_prepare_generation_plan', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_load_input_sources',
            description=(
                'Load data-agent input files or directories and extract structured paragraphs and table previews '
                'from xlsx, csv, docx, pdf, txt, md, json, or jsonl sources.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'paths': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Workspace-relative files or directories to load.',
                    },
                    'max_files': {'type': 'integer', 'minimum': 1, 'maximum': 100},
                    'max_paragraphs_per_file': {'type': 'integer', 'minimum': 1, 'maximum': 300},
                    'max_tables_per_file': {'type': 'integer', 'minimum': 1, 'maximum': 100},
                    'max_rows_per_table': {'type': 'integer', 'minimum': 1, 'maximum': 200},
                    'max_cell_chars': {'type': 'integer', 'minimum': 20, 'maximum': 2000},
                },
                'required': ['paths'],
            },
            handler=resolve_handler(handlers, 'data_agent_load_input_sources', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_extract_case_evidence',
            description=(
                'Extract query/badcase evidence from loaded input sources or source paths. '
                'Profiles table columns first and returns required questions when query or expected label columns are ambiguous.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'paths': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Workspace-relative files or directories. Omit when loaded_sources is provided.',
                    },
                    'loaded_sources': {
                        'type': 'object',
                        'description': 'Output from data_agent_load_input_sources.',
                    },
                    'field_mapping': {
                        'type': 'object',
                        'description': 'Optional role-to-column mapping, e.g. {"query":"query","expected_label":"预期domain"}.',
                    },
                    'max_cases': {'type': 'integer', 'minimum': 1, 'maximum': 1000},
                },
            },
            handler=resolve_handler(handlers, 'data_agent_extract_case_evidence', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_render_source_context',
            description=(
                'Render loaded data-agent sources into LLM-readable evidence text with source refs. '
                'Use this after data_agent_load_input_sources before asking the model to structure product semantics.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'paths': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Workspace-relative files or directories. Omit when loaded_sources is provided.',
                    },
                    'loaded_sources': {
                        'type': 'object',
                        'description': 'Output from data_agent_load_input_sources.',
                    },
                    'max_chars': {'type': 'integer', 'minimum': 1000, 'maximum': 200000},
                    'max_tables_per_source': {'type': 'integer', 'minimum': 1, 'maximum': 100},
                    'max_rows_per_table': {'type': 'integer', 'minimum': 1, 'maximum': 200},
                    'focus_keywords': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Optional keywords used to keep only matching paragraphs/table rows.',
                    },
                },
            },
            handler=resolve_handler(handlers, 'data_agent_render_source_context', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_show_generation_plan',
            description='Show a data-agent generation plan for human review.',
            parameters={
                'type': 'object',
                'properties': {
                    'plan_id': {'type': 'string'},
                },
                'required': ['plan_id'],
            },
            handler=resolve_handler(handlers, 'data_agent_show_generation_plan', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_update_generation_plan',
            description=(
                'Update a pending data-agent generation plan from human review feedback, then show it again for review.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'plan_id': {'type': 'string'},
                    'review_feedback': {
                        'type': 'string',
                        'description': 'Human review feedback that explains why the plan is changing.',
                    },
                    'updates': {
                        'type': 'object',
                        'description': 'Fields to update on the plan.',
                    },
                },
                'required': ['plan_id', 'review_feedback', 'updates'],
            },
            handler=resolve_handler(handlers, 'data_agent_update_generation_plan', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_confirm_generation_plan',
            description=(
                'Mark a pending data-agent generation plan as confirmed after the user explicitly approves it.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'plan_id': {'type': 'string'},
                    'confirmation': {
                        'type': 'string',
                        'description': 'The user approval text, such as 确认, 开始生成, or approve.',
                    },
                    'reviewed_revision': {
                        'type': 'integer',
                        'description': 'The plan revision shown to the user before confirmation.',
                    },
                },
                'required': ['plan_id', 'confirmation'],
            },
            handler=resolve_handler(handlers, 'data_agent_confirm_generation_plan', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_normalize_dataset_draft',
            description=(
                'Parse dataset draft text written with 用户/小爱/target blocks and build canonical '
                'data-agent records with generated record IDs, timestamps, source metadata, context, labels, '
                'and dimensions.complex. '
                'Generated data requires a confirmed_plan_id from data_agent_confirm_generation_plan. '
                'Use draft_path instead of draft_text when the draft is large or contains many quoted targets.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'draft_text': {
                        'type': 'string',
                        'description': 'Dataset draft text in dataset draft text v1 format. Each case should include complex: true/false. Provide exactly one of draft_text or draft_path.',
                    },
                    'draft_path': {
                        'type': 'string',
                        'description': 'Path to a UTF-8 dataset draft text file. Prefer this for large drafts. Provide exactly one of draft_text or draft_path.',
                    },
                    'batch_id': {
                        'type': 'string',
                        'description': 'Batch identifier used in generated record_id values.',
                    },
                    'source_type': {
                        'type': 'string',
                        'enum': ['generated', 'online', 'manual', 'mixed'],
                    },
                    'base_timestamp': {
                        'type': 'integer',
                        'description': 'Optional millisecond timestamp for deterministic generated records.',
                    },
                    'timestamp_step_ms': {
                        'type': 'integer',
                        'minimum': 1,
                        'description': 'Millisecond gap between adjacent turns. Defaults to 60000.',
                    },
                    'default_request_id': {
                        'type': 'string',
                        'description': 'Request ID to use when a case does not provide a real request_id.',
                    },
                    'confirmed_plan_id': {
                        'type': 'string',
                        'description': 'Required for generated data; returned by data_agent_confirm_generation_plan.',
                    },
                },
            },
            handler=resolve_handler(handlers, 'data_agent_normalize_dataset_draft', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_validate_dataset_records',
            description=(
                'Validate canonical data-agent records for required fields, labels, source metadata, '
                'prev_session structure, dimensions.complex, timestamp order, and 5-minute prompt stitching constraints.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'records': {
                        'oneOf': [
                            {'type': 'array'},
                            {'type': 'string'},
                        ],
                        'description': 'Canonical records as an array, or a JSON string containing the array. Provide exactly one of records or records_path.',
                    },
                    'records_path': {
                        'type': 'string',
                        'description': 'Path to records JSON/JSONL. Prefer this when records are large. Provide exactly one of records or records_path.',
                    },
                },
            },
            handler=resolve_handler(handlers, 'data_agent_validate_dataset_records', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_export_dataset_records',
            description=(
                'Validate canonical data-agent records and write them to a workspace file. '
                'Defaults to compact JSONL, one canonical record per line, and also writes records.csv '
                'in the same output directory for human sharing. The table function column combines '
                'complex=true/false and label.target.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'records': {
                        'oneOf': [
                            {'type': 'array'},
                            {'type': 'string'},
                        ],
                        'description': 'Canonical records as an array, or a JSON string containing the array. Provide exactly one of records or records_path.',
                    },
                    'records_path': {
                        'type': 'string',
                        'description': 'Path to records JSON/JSONL. Prefer this when records are large. Provide exactly one of records or records_path.',
                    },
                    'output_path': {
                        'type': 'string',
                        'description': (
                            'Requested workspace-relative path. For canonical records, the runtime normalizes this '
                            'to the current session output/records.jsonl or output/records.json; do not encode '
                            'dataset names or timestamps in the filename.'
                        ),
                    },
                    'output_format': {
                        'type': 'string',
                        'enum': ['jsonl', 'json'],
                        'description': 'Defaults to jsonl. json writes a compact JSON array.',
                    },
                    'require_validation_ok': {
                        'type': 'boolean',
                        'description': 'When true, refuse to write records with validation errors.',
                    },
                    'overwrite': {
                        'type': 'boolean',
                        'description': 'When false, refuse to overwrite an existing file.',
                    },
                    'export_table': {
                        'type': 'boolean',
                        'description': 'Defaults to true. Also write records.csv with the shared spreadsheet columns.',
                    },
                },
                'required': ['output_path'],
            },
            handler=resolve_handler(handlers, 'data_agent_export_dataset_records', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_export_training_jsonl',
            description=(
                'Convert canonical data-agent records into training JSONL. Each line has system, instruction, '
                'and output. Output combines dimensions.complex and label.target as two lines. '
                'The instruction contains 知识注入, 系统状态, 对话历史, 当前query, and function sections.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'records': {
                        'oneOf': [
                            {'type': 'array'},
                            {'type': 'string'},
                        ],
                        'description': 'Canonical records as an array, or a JSON string containing the array. Provide exactly one of records or records_path.',
                    },
                    'records_path': {
                        'type': 'string',
                        'description': 'Path to records JSON/JSONL. Prefer this when records are large. Provide exactly one of records or records_path.',
                    },
                    'output_path': {
                        'type': 'string',
                        'description': 'Optional requested path. Runtime normalizes to current session output/training.jsonl.',
                    },
                    'session_num': {
                        'type': 'integer',
                        'minimum': 1,
                        'description': 'Max history queries to include. Defaults to 5.',
                    },
                    'session_time_minutes': {
                        'type': 'integer',
                        'minimum': 1,
                        'description': 'Max adjacent history gap in minutes. Defaults to 5.',
                    },
                    'context_fields': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Context fields to inject. Defaults to ["location", "rag"].',
                    },
                    'system_prompt': {
                        'type': 'string',
                        'description': 'Defaults to 你是小爱同学，中文智能语音助手。',
                    },
                    'require_validation_ok': {'type': 'boolean'},
                    'overwrite': {'type': 'boolean'},
                },
            },
            handler=resolve_handler(handlers, 'data_agent_export_training_jsonl', 'data-agent'),
        ),
        AgentTool(
            name='data_agent_export_planning_eval_csv',
            description=(
                'Convert canonical data-agent records into evaluation CSV with columns: request_id, newPrompt, '
                'query, 类别真实标签, code标签, complex. The complex column is read from dimensions.complex. '
                'newPrompt wraps the prompt body with <|im_start|>system/user/assistant chat-template tags.'
            ),
            parameters={
                'type': 'object',
                'properties': {
                    'records': {
                        'oneOf': [
                            {'type': 'array'},
                            {'type': 'string'},
                        ],
                        'description': 'Canonical records as an array, or a JSON string containing the array. Provide exactly one of records or records_path.',
                    },
                    'records_path': {
                        'type': 'string',
                        'description': 'Path to records JSON/JSONL. Prefer this when records are large. Provide exactly one of records or records_path.',
                    },
                    'output_path': {
                        'type': 'string',
                        'description': 'Optional requested path. Runtime normalizes to current session output/eval_planning.csv.',
                    },
                    'session_num': {
                        'type': 'integer',
                        'minimum': 1,
                        'description': 'Max history queries to include. Defaults to 5.',
                    },
                    'session_time_minutes': {
                        'type': 'integer',
                        'minimum': 1,
                        'description': 'Max adjacent history gap in minutes. Defaults to 5.',
                    },
                    'context_fields': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'description': 'Context fields to inject. Defaults to ["location", "rag"].',
                    },
                    'system_prompt': {
                        'type': 'string',
                        'description': 'System prompt wrapped into newPrompt chat template. Defaults to 你是小爱同学，中文智能语音助手。',
                    },
                    'complex_default': {
                        'type': 'boolean',
                        'description': 'Fallback complex value only for legacy records missing dimensions.complex. Defaults to false.',
                    },
                    'require_validation_ok': {'type': 'boolean'},
                    'overwrite': {'type': 'boolean'},
                },
            },
            handler=resolve_handler(handlers, 'data_agent_export_planning_eval_csv', 'data-agent'),
        ),
    ]
