package PDK::Connector::Paloalto;

use utf8;
use v5.30;
use Moose;
use Carp;
use Data::Dumper;

# 继承连接器常用功能
with 'PDK::Connector::Role';

# 登录成功提示符（Paloalto设备特有格式）
has prompt => (
    is       => 'ro',
    required => 0,
    default  => '^.*?\((?:active|passive|suspended)\)[>#]\s*$', # 匹配Paloalto设备的提示符格式（包含HA状态）
);

# 特权模式状态标志（Paloalto设备默认进入特权模式）
has _enable_ => (
    is       => 'ro',
    required => 0,
    default  => 1, # Paloalto设备默认进入特权模式
);

# 等待设备响应，处理各种交互提示
sub waitfor {
    my ($self, $prompt) = @_;
    $prompt = $prompt // $self->{$prompt}; # 使用提供的提示符或默认提示符

    my $exp = $self->{exp};
    my $buff = "";

    # 等待设备响应，处理各种交互提示
    my @ret = $exp->expect($self->{timeout},
        # 处理分页提示（Paloalto特有格式）
        [ qr/^lines\s*\d+-\d+\s*$/i => sub {
            $self->send(" "); # 发送空格继续显示
            $buff .= $exp->before();
            exp_continue;
        } ],
        # 处理确认提示
        [ qr/are you sure\?/i => sub {
            $self->send("y\r"); # 发送y确认
            $buff .= $exp->before() . $exp->match();
            exp_continue;
        } ],
        # 匹配命令提示符
        [ qr/$prompt/m => sub {
            $buff .= $exp->before() . $exp->match(); # 保存完整输出
        } ]
    );

    # 检查Expect操作是否出错
    if (defined $ret[1]) {
        croak("[等待回显期间异常]" . $ret[3] . $ret[1]);
    }

    # 清理输出内容（Paloalto设备特有控制字符）
    $buff =~ s/ \cH//g;                  # 移除空格后跟退格符（常用于终端覆盖显示）
    $buff =~ s/(\c[\S+)+\cM(\c[\[K)?//g; # 移除ANSI转义序列和回车符（控制光标位置和清除行）
    $buff =~ s/\cM(\c[\S+)+\c[>//g;      # 移除包含回车符的复杂ANSI序列（通常是终端提示符相关）

    return $buff;
}

# 执行多个命令
sub execCommands {
    my ($self, $commands) = @_;

    # 检查登录状态，如果未登录则先登录
    if (!$self->{_login_}) {
        my $ret = $self->login();
        return $ret unless $ret->{success};
    }

    my $result = '';
    # 逐个执行命令
    for my $cmd (@{$commands}) {
        $self->send("$cmd\n");

        # 检查命令是否执行失败（Paloalto特有错误消息）
        my $buff = $self->waitfor();
        if ($buff =~ /(^Error:|Unknown command|Invalid syntax)/i) {
            return {
                success     => 0,
                failCommand => $cmd,
                result      => $result,
                reason      => $result . $buff
            };
        }
        else {
            $result .= $buff; # 保存命令执行结果
        }
    }

    return { success => 1, result => $result };
}

# 获取设备配置方法（Paloalto特有命令）
sub getConfig {
    my $self = shift;
    my $commands = [
        "set cli pager off",                # 禁用分页
        "set cli config-output-format set", # 设置配置输出格式为set命令格式
        "configure",                        # 进入配置模式
        "show",                             # 显示配置
        "quit"                              # 退出配置模式
    ];
    my $config = $self->execCommands($commands);
    my $lines = "";

    if ($config->{success} == 1) {
        $lines = $config->{result};
    }
    else {
        return $config; # 返回错误信息
    }

    return { success => 1, config => $lines };
}

# 使Moose类不可变
__PACKAGE__->meta->make_immutable;
1;
