from dataclasses import dataclass

import typer

from cli.context import CliContext, OutputOption
from cli.wizard.base import BaseCliWizardFlow


@dataclass(frozen=True)
class GenImportWizardSelection:
    """
    `wizard gen-import` 向导采集结果。

    :param env: 运行环境
    :param table_names: 待导入物理表名称列表
    :param dry_run: 是否演练执行
    :param allow_prod: 是否允许生产环境执行
    """

    env: str
    table_names: list[str]
    dry_run: bool
    allow_prod: bool


class GenImportWizardFlow(BaseCliWizardFlow[GenImportWizardSelection]):
    """
    `wizard gen-import` 向导流程。

    :param default_env: 默认环境
    :param default_table_names: 默认物理表名称列表文本
    :param default_dry_run: 默认是否先执行 dry-run
    """

    wizard_name = 'wizard gen-import'
    preview_title = 'wizard gen-import preview'
    failure_message = '代码生成导入向导执行失败'

    def __init__(
        self,
        *,
        default_env: str = 'dev',
        default_table_names: str = '',
        default_dry_run: bool = True,
    ) -> None:
        """
        初始化代码生成导入向导流程。

        :param default_env: 默认环境
        :param default_table_names: 默认物理表名称列表文本
        :param default_dry_run: 默认是否先执行 dry-run
        :return: None
        """
        self.default_env = default_env
        self.default_table_names = default_table_names
        self.default_dry_run = default_dry_run

    def collect_selection(self) -> GenImportWizardSelection:
        """
        采集代码生成导入向导参数。

        :return: 向导采集结果
        """
        env = self.prompt_service.prompt_env(self.default_env)
        raw_table_names = self.prompt_service.prompt_required_text(
            '物理表名称列表（多个表请使用逗号分隔）',
            self.default_table_names,
        )
        table_names = self.parse_table_names(raw_table_names)
        while not table_names:
            typer.echo('至少需要输入一个物理表名称，请重新输入。')
            raw_table_names = self.prompt_service.prompt_required_text(
                '物理表名称列表（多个表请使用逗号分隔）',
                self.default_table_names,
            )
            table_names = self.parse_table_names(raw_table_names)

        dry_run = self.prompt_service.prompt_confirm('是否先执行 dry-run 预演', default_value=self.default_dry_run)
        allow_prod = (
            self.prompt_service.prompt_confirm('当前为 prod 环境，是否允许继续执行', default_value=False)
            if env == 'prod'
            else False
        )
        return GenImportWizardSelection(
            env=env,
            table_names=table_names,
            dry_run=dry_run,
            allow_prod=allow_prod,
        )

    def prepare_context(self, selection: GenImportWizardSelection, output: OutputOption) -> CliContext:
        """
        构建代码生成导入向导上下文。

        :param selection: 向导采集结果
        :param output: 输出格式
        :return: CLI 上下文
        """
        return self.build_regular_context(
            selection.env,
            output,
            allow_prod=selection.allow_prod,
            yes=True,
            dry_run=selection.dry_run,
        )

    def build_preview_summary(self, selection: GenImportWizardSelection) -> dict[str, str]:
        """
        构建代码生成导入预览摘要。

        :param selection: 向导采集结果
        :return: 预览摘要
        """
        return {
            'env': selection.env,
            'table_names': ','.join(selection.table_names),
            'dry_run': str(selection.dry_run).lower(),
            'allow_prod': str(selection.allow_prod).lower(),
        }

    def build_preview_command(self, selection: GenImportWizardSelection) -> list[str]:
        """
        构建代码生成导入预览命令。

        :param selection: 向导采集结果
        :return: 用户视角命令参数
        """
        command = ['shierfeng', 'gen', 'import-table', *selection.table_names, f'--env={selection.env}']
        if selection.dry_run:
            command.append('--dry-run')
        if selection.allow_prod:
            command.append('--allow-prod')
        return command

    def build_preview_notes(self, selection: GenImportWizardSelection) -> list[str] | None:
        """
        构建代码生成导入预览附加说明。

        :param selection: 向导采集结果
        :return: 预览附加说明
        """
        del selection
        return ['建议先确认物理表注释和字段规模，再决定是否执行真实导入。']

    def confirm_prompt(self, selection: GenImportWizardSelection) -> str:
        """
        返回代码生成导入最终确认提示。

        :param selection: 向导采集结果
        :return: 确认提示
        """
        del selection
        return '确认执行代码生成导入向导吗'

    def build_execute_arguments(self, selection: GenImportWizardSelection, output: OutputOption) -> list[str]:
        """
        构建代码生成导入内部 CLI 参数。

        :param selection: 向导采集结果
        :param output: 输出格式
        :return: 内部 CLI 参数
        """
        arguments = [
            'gen',
            'import-table',
            *selection.table_names,
            f'--env={selection.env}',
            f'--output={output}',
            '--yes',
        ]
        if selection.dry_run:
            arguments.append('--dry-run')
        if selection.allow_prod:
            arguments.append('--allow-prod')
        return arguments

    @staticmethod
    def parse_table_names(raw_value: str) -> list[str]:
        """
        将逗号分隔的物理表名称文本解析为列表。

        :param raw_value: 原始输入文本
        :return: 去空白后的物理表名称列表
        """
        return [table_name.strip() for table_name in raw_value.split(',') if table_name.strip()]


def run_gen_import_wizard(
    output: OutputOption = 'text',
    *,
    default_env: str = 'dev',
    default_table_names: str = '',
    default_dry_run: bool = True,
) -> None:
    """
    执行 `wizard gen-import` 向导。

    :param output: 输出格式
    :param default_env: 默认环境
    :param default_table_names: 默认物理表名称列表文本
    :param default_dry_run: 默认是否先 dry-run
    :return: None
    """
    GenImportWizardFlow(
        default_env=default_env,
        default_table_names=default_table_names,
        default_dry_run=default_dry_run,
    ).run(output)
