from dataclasses import dataclass

import typer

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


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

    :param env: 运行环境
    :param table_names: 业务表名称列表
    :param mode: 导出模式
    :param output_file: zip 导出目标文件路径
    :param dry_run: 是否演练执行
    :param allow_prod: 是否允许生产环境执行
    """

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


class GenExportWizardFlow(BaseCliWizardFlow[GenExportWizardSelection]):
    """
    `wizard gen-export` 向导流程。

    :param default_env: 默认环境
    :param default_table_names: 默认业务表名称列表文本
    :param default_mode: 默认导出模式
    :param default_output_file: 默认 zip 导出目标文件路径
    :param default_dry_run: 默认是否先执行 dry-run
    """

    wizard_name = 'wizard gen-export'
    preview_title = 'wizard gen-export preview'
    failure_message = '代码导出向导执行失败'

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

        :param default_env: 默认环境
        :param default_table_names: 默认业务表名称列表文本
        :param default_mode: 默认导出模式
        :param default_output_file: 默认 zip 导出目标文件路径
        :param default_dry_run: 默认是否先执行 dry-run
        :return: None
        """
        self.default_env = default_env
        self.default_table_names = default_table_names
        self.default_mode = default_mode
        self.default_output_file = default_output_file
        self.default_dry_run = default_dry_run

    def collect_selection(self) -> GenExportWizardSelection:
        """
        采集代码导出向导参数。

        :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)

        mode = self.prompt_service.prompt_choice('导出模式', ['zip', 'local'], self.default_mode)
        output_file = ''
        if mode == 'zip':
            output_file = self.prompt_service.prompt_optional_text(
                'zip 导出目标文件路径（留空则使用默认文件名）',
                self.default_output_file,
            )
        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 GenExportWizardSelection(
            env=env,
            table_names=table_names,
            mode=mode,
            output_file=output_file,
            dry_run=dry_run,
            allow_prod=allow_prod,
        )

    def prepare_context(self, selection: GenExportWizardSelection, 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: GenExportWizardSelection) -> dict[str, str]:
        """
        构建代码导出预览摘要。

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

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

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

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

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

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

        :param selection: 向导采集结果
        :param output: 输出格式
        :return: 内部 CLI 参数
        """
        arguments = [
            'gen',
            'export',
            *selection.table_names,
            f'--env={selection.env}',
            f'--output={output}',
            f'--mode={selection.mode}',
            '--yes',
        ]
        if selection.output_file:
            arguments.append(f'--output-file={selection.output_file}')
        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_export_wizard(
    output: OutputOption = 'text',
    *,
    default_env: str = 'dev',
    default_table_names: str = '',
    default_mode: str = 'zip',
    default_output_file: str = '',
    default_dry_run: bool = True,
) -> None:
    """
    执行 `wizard gen-export` 向导。

    :param output: 输出格式
    :param default_env: 默认环境
    :param default_table_names: 默认业务表名称列表文本
    :param default_mode: 默认导出模式
    :param default_output_file: 默认 zip 导出目标文件路径
    :param default_dry_run: 默认是否先 dry-run
    :return: None
    """
    GenExportWizardFlow(
        default_env=default_env,
        default_table_names=default_table_names,
        default_mode=default_mode,
        default_output_file=default_output_file,
        default_dry_run=default_dry_run,
    ).run(output)
