---
- name: Развернуть TSJ Guardian Telegram Bot на Proxmox
  hosts: proxmox
  become: true
  gather_facts: true

  vars:
    tsj_bot_runtime_root: "/opt/infra-admin"
    tsj_bot_user: "root"
    tsj_bot_group: "admin"
    tsj_bot_root: "{{ tsj_bot_runtime_root }}/tsj-bot"
    tsj_bot_script_name: "tsj_guardian_bot.py"
    tsj_bot_script_dest: "{{ tsj_bot_root }}/{{ tsj_bot_script_name }}"
    tsj_bot_source_local_path: "{{ aw_repo_root }}/proxmox/tsj_guardian_bot.py"
    tsj_bot_watchdog_name: "tsj_guardian_watchdog.sh"
    tsj_bot_watchdog_dest: "{{ tsj_bot_root }}/{{ tsj_bot_watchdog_name }}"
    tsj_bot_watchdog_source_local_path: "{{ aw_repo_root }}/proxmox/{{ tsj_bot_watchdog_name }}"
    tsj_bot_watchdog_service_name: "tsj-guardian-watchdog.service"
    tsj_bot_openvpn_helper_name: "pfsense_openvpn_client_export.php"
    tsj_bot_openvpn_helper_dest: "{{ tsj_bot_root }}/{{ tsj_bot_openvpn_helper_name }}"
    tsj_bot_openvpn_helper_source_local_path: "{{ aw_repo_root }}/proxmox/{{ tsj_bot_openvpn_helper_name }}"
    tsj_bot_service_name: "tsj-guardian-bot.service"
    tsj_bot_env_path: "{{ tsj_bot_root }}/.env"
    tsj_bot_state_dir: "{{ tsj_bot_runtime_root }}/.state"
    tsj_bot_logs_dir: "{{ tsj_bot_runtime_root }}/logs"
    tsj_bot_default_chat_id: "{{ telegram_default_chat_id | default(telegram_allowed_chat_ids.split(',')[0]) }}"
    aw_rust_release_dir: "{{ (lookup('env', 'CARGO_TARGET_DIR') | default(aw_repo_root + '/adk-rust/target', true)) + '/release' }}"
    tsj_guardian_status_required_flags:
      - "--status-text"
      - "--incident-suggestions"
      - "--incident-defer-decision"
      - "--escalation-decision"
      - "--operator-action-decision"
      - "--dlp-policy-decision"
      - "--confirmation-decision"
      - "--autoheal-plan-decision"

  pre_tasks:
    - name: Проверить наличие существующего .env бота на хосте
      ansible.builtin.stat:
        path: "{{ tsj_bot_env_path }}"
      register: tsj_bot_existing_env

    - name: Проверить обязательные переменные
      ansible.builtin.assert:
        that:
          - >
            (
              telegram_bot_token is defined and
              (telegram_bot_token | string | length) > 20 and
              telegram_allowed_chat_ids is defined and
              (telegram_allowed_chat_ids | string | length) > 0
            )
            or
            (tsj_bot_existing_env.stat.exists | default(false))
        fail_msg: "Задайте telegram_bot_token и telegram_allowed_chat_ids или оставьте на хосте существующий {{ tsj_bot_env_path }}."

    - name: Проверить наличие исходного файла бота на контроллере
      ansible.builtin.stat:
        path: "{{ tsj_bot_source_local_path }}"
      register: tsj_bot_source_stat
      delegate_to: localhost
      become: false

    - name: Остановить выполнение если файл бота не найден на контроллере
      ansible.builtin.assert:
        that:
          - tsj_bot_source_stat.stat.exists
          - tsj_bot_source_stat.stat.isreg
        fail_msg: "Файл бота не найден: {{ tsj_bot_source_local_path }}"

    - name: Проверить наличие helper для OpenVPN экспорта на контроллере
      ansible.builtin.stat:
        path: "{{ tsj_bot_openvpn_helper_source_local_path }}"
      register: tsj_bot_openvpn_helper_stat
      delegate_to: localhost
      become: false

    - name: Проверить наличие watchdog скрипта на контроллере
      ansible.builtin.stat:
        path: "{{ tsj_bot_watchdog_source_local_path }}"
      register: tsj_bot_watchdog_stat
      delegate_to: localhost
      become: false

    - name: Проверить локальный Rust TSJ guardian status helper
      ansible.builtin.stat:
        path: "{{ aw_rust_release_dir }}/tsj-guardian-status"
      register: tsj_guardian_status_rust_binary
      delegate_to: localhost
      become: false

    - name: Остановить выполнение если Rust TSJ guardian status helper не найден
      ansible.builtin.assert:
        that:
          - tsj_guardian_status_rust_binary.stat.exists
          - tsj_guardian_status_rust_binary.stat.isreg
        fail_msg: "Rust helper не найден: {{ aw_rust_release_dir }}/tsj-guardian-status. Соберите binary и проверьте CARGO_TARGET_DIR."

    - name: Проверить контракт локального Rust TSJ guardian status helper
      ansible.builtin.command:
        cmd: "{{ aw_rust_release_dir }}/tsj-guardian-status --help"
      register: tsj_guardian_status_help
      changed_when: false
      delegate_to: localhost
      become: false

    - name: Остановить выполнение если Rust TSJ guardian status helper устарел
      ansible.builtin.assert:
        that:
          - item in tsj_guardian_status_help.stdout
        fail_msg: "Rust helper {{ aw_rust_release_dir }}/tsj-guardian-status не поддерживает {{ item }}. Проверьте CARGO_TARGET_DIR и пересоберите helper."
      loop: "{{ tsj_guardian_status_required_flags }}"

    - name: Остановить выполнение если helper для OpenVPN не найден
      ansible.builtin.assert:
        that:
          - tsj_bot_openvpn_helper_stat.stat.exists
          - tsj_bot_openvpn_helper_stat.stat.isreg
        fail_msg: "Файл helper для OpenVPN не найден: {{ tsj_bot_openvpn_helper_source_local_path }}"

    - name: Остановить выполнение если watchdog не найден
      ansible.builtin.assert:
        that:
          - tsj_bot_watchdog_stat.stat.exists
          - tsj_bot_watchdog_stat.stat.isreg
        fail_msg: "Файл watchdog не найден: {{ tsj_bot_watchdog_source_local_path }}"

  tasks:
    - name: Установить зависимости Python для бота
      ansible.builtin.package:
        name:
          - python3
          - python3-requests
          - sshpass
        state: present

    - name: Создать каталоги бота
      ansible.builtin.file:
        path: "{{ item.path }}"
        state: directory
        owner: "{{ item.owner | default(tsj_bot_user) }}"
        group: "{{ item.group | default(tsj_bot_group) }}"
        mode: "{{ item.mode }}"
      loop:
        - { path: "{{ tsj_bot_root }}", mode: "0775" }
        - { path: "{{ tsj_bot_state_dir }}", mode: "0775" }
        - { path: "{{ tsj_bot_logs_dir }}", mode: "0775" }

    - name: Развернуть скрипт бота
      ansible.builtin.copy:
        src: "{{ tsj_bot_source_local_path }}"
        dest: "{{ tsj_bot_script_dest }}"
        owner: root
        group: "{{ tsj_bot_group }}"
        mode: "0750"
      notify: Restart tsj bot

    - name: Развернуть Rust helper статуса TSJ guardian
      ansible.builtin.copy:
        src: "{{ aw_rust_release_dir }}/tsj-guardian-status"
        dest: /usr/local/bin/tsj-guardian-status
        owner: root
        group: root
        mode: "0755"
      when: tsj_guardian_status_rust_binary.stat.exists | default(false)
      notify: Restart tsj bot

    - name: Развернуть helper для OpenVPN экспорта
      ansible.builtin.copy:
        src: "{{ tsj_bot_openvpn_helper_source_local_path }}"
        dest: "{{ tsj_bot_openvpn_helper_dest }}"
        owner: root
        group: "{{ tsj_bot_group }}"
        mode: "0640"
      notify: Restart tsj bot

    - name: Развернуть watchdog скрипт бота
      ansible.builtin.copy:
        src: "{{ tsj_bot_watchdog_source_local_path }}"
        dest: "{{ tsj_bot_watchdog_dest }}"
        owner: root
        group: root
        mode: "0755"

    - name: Сгенерировать полный .env бота
      when:
        - telegram_bot_token is defined
        - (telegram_bot_token | string | length) > 20
        - telegram_allowed_chat_ids is defined
        - (telegram_allowed_chat_ids | string | length) > 0
      no_log: true
      ansible.builtin.copy:
        dest: "{{ tsj_bot_env_path }}"
        owner: "{{ tsj_bot_user }}"
        group: "{{ tsj_bot_group }}"
        mode: "0640"
        content: |
          TELEGRAM_BOT_TOKEN={{ telegram_bot_token }}
          TELEGRAM_ALLOWED_CHAT_IDS={{ telegram_allowed_chat_ids }}
          TELEGRAM_DEFAULT_CHAT_ID={{ tsj_bot_default_chat_id }}
          HTTPS_PROXY={{ tsj_bot_https_proxy_url | default(tsj_bot_telegram_proxy_url | default('http://127.0.0.1:11090')) }}
          HTTP_PROXY={{ tsj_bot_http_proxy_url | default(tsj_bot_telegram_proxy_url | default('http://127.0.0.1:11090')) }}
          NO_PROXY={{ tsj_bot_no_proxy | default('localhost,127.0.0.1,192.0.2.0/24') }}
          NODE_13_HOST={{ tsj_bot_node_13_host | default('192.0.2.13') }}
          NODE_16_HOST={{ tsj_bot_node_16_host | default('192.0.2.16') }}
          NODE_13_URL={{ tsj_bot_node_13_url | default('http://192.0.2.13:5600/api/0/info') }}
          NODE_16_URL={{ tsj_bot_node_16_url | default('http://192.0.2.16/') }}
          NODE_16_ENABLED={{ tsj_bot_node_16_enabled | default('false') }}
          INFRA_ADMIN_ROOT={{ tsj_bot_runtime_root }}
          CHECK_SCRIPT={{ tsj_bot_check_script | default(tsj_bot_runtime_root + '/scripts/system_self_support.sh --check') }}
          HEAL_SCRIPT={{ tsj_bot_heal_script | default(tsj_bot_runtime_root + '/scripts/system_self_support.sh --heal') }}
          FS_WARN_PCT={{ tsj_bot_fs_warn_pct | default(85) }}
          FS_CRIT_PCT={{ tsj_bot_fs_crit_pct | default(92) }}
          FS_TARGETS={{ tsj_bot_fs_targets | default('host,200,201,202,203') }}
          FS_EXCLUDE_TYPES={{ tsj_bot_fs_exclude_types | default('tmpfs,devtmpfs,proc,sysfs,cgroup,cgroup2,overlay,squashfs,nsfs,tracefs,debugfs,securityfs,configfs,fusectl,mqueue,hugetlbfs,ramfs') }}
          STATE_FILE={{ tsj_bot_state_file | default(tsj_bot_runtime_root + '/.state/tsj_guardian_state.json') }}
          LOG_FILE={{ tsj_bot_log_file | default(tsj_bot_runtime_root + '/logs/tsj_guardian_bot.log') }}
          HEARTBEAT_FILE={{ tsj_bot_heartbeat_file | default(tsj_bot_runtime_root + '/.state/tsj_guardian_heartbeat') }}
          CHECK_INTERVAL_SEC={{ tsj_bot_check_interval_sec | default(60) }}
          INCIDENT_FAILURE_QUORUM_CHECKS={{ tsj_bot_incident_failure_quorum_checks | default(2) }}
          OPERATOR_TIMEOUT_SEC={{ tsj_bot_operator_timeout_sec | default(900) }}
          RETRY_AUTORECOVERY_EVERY_SEC={{ tsj_bot_retry_autorecovery_every_sec | default(300) }}
          EXIT_ON_AUTORECOVERY_SUCCESS={{ tsj_bot_exit_on_autorecovery_success | default('true') }}
          ENABLE_AI_ESCALATION={{ tsj_bot_enable_ai_escalation | default('true') }}
          FS_IMMEDIATE_AI_ON_CRITICAL={{ tsj_bot_fs_immediate_ai_on_critical | default('true') }}
          AI_ESCALATION_MODE={{ tsj_bot_ai_escalation_mode | default('codex_exec') }}
          ENABLE_SERVER_FALLBACK={{ tsj_bot_enable_server_fallback | default('true') }}
          TELEGRAM_PROXY_URL={{ tsj_bot_telegram_proxy_url | default('http://127.0.0.1:11090') }}
          AI_CHAT_ENABLED={{ tsj_bot_ai_chat_enabled | default('true') }}
          AI_CHAT_TIMEOUT_SEC={{ tsj_bot_ai_chat_timeout_sec | default(1800) }}
          AI_CHAT_WORKDIR={{ tsj_bot_ai_chat_workdir | default('~') }}
          AI_CHAT_SANDBOX={{ tsj_bot_ai_chat_sandbox | default('workspace-write') }}
          CODEX_MODEL={{ tsj_bot_codex_model | default('gpt-5.3-codex') }}
          CODEX_FALLBACK_MODELS={{ tsj_bot_codex_fallback_models | default('gpt-5.4-mini') }}
          AI_EXEC_USER={{ tsj_bot_ai_exec_user | default('igor') }}
          TMUX_USER={{ tsj_bot_tmux_user | default('igor') }}
          TMUX_SESSION={{ tsj_bot_tmux_session | default('ai') }}
          TMUX_CREATE_IF_MISSING={{ tsj_bot_tmux_create_if_missing | default('false') }}
          TMUX_START_COMMAND={{ tsj_bot_tmux_start_command | default('codex') }}
          PFSENSE_ENV_PATH={{ tsj_bot_pfsense_env_path | default('~/.config/tsj-bot/pfsense.env.readonly') }}
          PFSENSE_INVENTORY_PATH={{ tsj_bot_pfsense_inventory_path | default('~/.config/tsj-bot/inventory.md') }}
          PFSENSE_CHANGE_CONTROL_ENABLED={{ tsj_bot_pfsense_change_control_enabled | default('true') }}
          PFSENSE_CHANGE_CONFIRM_TTL_SEC={{ tsj_bot_pfsense_change_confirm_ttl_sec | default(900) }}
          OPENVPN_CONFIG_ENABLED={{ tsj_bot_openvpn_config_enabled | default('true') }}
          OPENVPN_CONFIG_CONFIRM_TTL_SEC={{ tsj_bot_openvpn_config_confirm_ttl_sec | default(900) }}
          OPENVPN_EXPIRY_WARN_ENABLED={{ tsj_bot_openvpn_expiry_warn_enabled | default('false') }}
          OPENVPN_EXPIRY_WARN_DAYS={{ tsj_bot_openvpn_expiry_warn_days | default(30) }}
          OPENVPN_EXPIRY_WARN_TIMEOUT_SEC={{ tsj_bot_openvpn_expiry_warn_timeout_sec | default(120) }}
          OPENVPN_EXPIRY_WARN_INTERVAL_SEC={{ tsj_bot_openvpn_expiry_warn_interval_sec | default(21600) }}
          PFSENSE_MCP_BEARER={{ tsj_bot_pfsense_mcp_bearer | default(pfsense_mcp_bearer | default('')) }}
          SERVER_FALLBACK_COMMANDS={{ tsj_bot_server_fallback_commands | default(tsj_bot_runtime_root + '/scripts/system_self_support.sh --heal') }}
          UPDATES_SCRIPT={{ tsj_bot_updates_script | default('/usr/bin/python3 ' + tsj_bot_runtime_root + '/scripts/proxmox_lxc_critical_updates.py') }}
          UPDATE_TARGETS={{ tsj_bot_update_targets | default('auto') }}
          DETMIR_AI_STATE_FILE={{ tsj_bot_detmir_ai_state_file | default('/var/lib/detmir-ai/latest-state.json') }}
          TSJ_GUARDIAN_STATUS_BIN={{ tsj_bot_guardian_status_bin | default('/usr/local/bin/tsj-guardian-status') }}
          AW_RUS_API_BASE={{ tsj_bot_aw_rus_api_base | default('http://192.0.2.13:5600/api/0') }}
          AW_RUS_WORKTIME_BASE={{ tsj_bot_aw_rus_worktime_base | default('http://192.0.2.13:5610') }}
          AW_DLP_POLICY_API_BASE={{ tsj_bot_aw_dlp_policy_api_base | default('http://192.0.2.13:5601/api/0') }}
          AW_DLP_POLICY_ACTOR={{ tsj_bot_aw_dlp_policy_actor | default('tsj-guardian-bot') }}
          AW_RUS_WORKTIME_HEAL_CMD={{ tsj_bot_aw_rus_worktime_heal_cmd | default("ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'sudo -n /usr/local/bin/aw-worktime-autoheal-rust && sudo -n systemctl reset-failed aw-worktime-ui-bridge.service && sudo -n systemctl start aw-worktime-ui-bridge.service'") }}
          AW_RUS_DLP_HEAL_CMD={{ tsj_bot_aw_rus_dlp_heal_cmd | default("ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'sudo -n systemctl restart activitywatch-server.service && (sudo -n systemctl start activitywatch-dlp-aggregator.service || true) && sudo -n /usr/local/bin/aw-health-check && sudo -n /usr/local/bin/dlp-health-check'") }}
          AW_RUS_CASE_API_BASE={{ tsj_bot_aw_rus_case_api_base | default('http://192.0.2.13:5602') }}
          AW_RUS_HAYABUSA_ENABLED={{ tsj_bot_aw_rus_hayabusa_enabled | default('true') }}
          AW_RUS_HAYABUSA_SSH_CMD={{ tsj_bot_aw_rus_hayabusa_ssh_cmd | default("ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13") }}
          AW_RUS_HOST={{ tsj_bot_aw_rus_host | default('HOST-EXAMPLE') }}
          AW_RUS_PRIMARY_USER={{ tsj_bot_aw_rus_primary_user | default('USER1') }}
          AW_RUS_STALE_SEC={{ tsj_bot_aw_rus_stale_sec | default(900) }}
          AW_RUS_SLO_ENABLED={{ tsj_bot_aw_rus_slo_enabled | default('true') }}
          AW_RUS_SLO_ALERT_WINDOW={{ tsj_bot_aw_rus_slo_alert_window | default('24h') }}
          AW_RUS_SLO_MIN_SAMPLES={{ tsj_bot_aw_rus_slo_min_samples | default(4) }}
          AW_RUS_SLO_MAX_AGE_SEC={{ tsj_bot_aw_rus_slo_max_age_sec | default(90) }}
          AW_RUS_SLO_SUMMARY_CMD={{ tsj_bot_aw_rus_slo_summary_cmd | default("ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'cat /var/lib/activitywatch/slo/aw-slo-summary.json'") }}
          AW_RUS_WINDOWS_HOST={{ tsj_bot_aw_rus_windows_host | default(hostvars[(groups['aw_windows'] | first)].ansible_host | default('198.51.100.18')) }}
          AW_RUS_WINDOWS_SSH_USER={{ tsj_bot_aw_rus_windows_ssh_user | default(hostvars[(groups['aw_windows'] | first)].ansible_user | default('Администратор')) }}
          AW_RUS_WINDOWS_SSH_PASSWORD={{ tsj_bot_aw_rus_windows_ssh_password | default(hostvars[(groups['aw_windows'] | first)].ansible_password | default('')) }}
          AW_RUS_WINDOWS_CONFIG_PATH={{ tsj_bot_aw_rus_windows_config_path | default('C:\ProgramData\AWatch-rus\deployment-config.json') }}
          AW_RUS_WINDOWS_HARDENING_RECOVERY_PATH={{ tsj_bot_aw_rus_windows_hardening_recovery_path | default('C:\Program Files\AWatch-rus\windows\hardening-recovery.ps1') }}
          AW_RUS_WINDOWS_SESSION_COLLECTOR_PATH={{ tsj_bot_aw_rus_windows_session_collector_path | default('C:\ProgramData\AWatch-rus\worktime-session-collector.ps1') }}
          AW_RUS_WINDOWS_POLICY_PATH={{ tsj_bot_aw_rus_windows_policy_path | default('C:\ProgramData\AWatch-rus\dlp-policy.json') }}
          AW_RUS_WINDOWS_BROWSER_COLLECTOR_PATH={{ tsj_bot_aw_rus_windows_browser_collector_path | default('C:\ProgramData\AWatch-rus\browser-domains-native-collector.ps1') }}
          AW_RUS_WINDOWS_EMAIL_COLLECTOR_PATH={{ tsj_bot_aw_rus_windows_email_collector_path | default('C:\ProgramData\AWatch-rus\email-outbound-collector.ps1') }}
      notify: Restart tsj bot

    - name: Обновить только AW-Rus/Hayabusa env ключи в существующем .env
      when:
        - not (
            telegram_bot_token is defined and
            (telegram_bot_token | string | length) > 20 and
            telegram_allowed_chat_ids is defined and
            (telegram_allowed_chat_ids | string | length) > 0
          )
        - tsj_bot_existing_env.stat.exists | default(false)
      no_log: true
      ansible.builtin.lineinfile:
        path: "{{ tsj_bot_env_path }}"
        regexp: "^{{ item.key }}="
        line: "{{ item.key }}={{ item.value }}"
        create: false
        owner: "{{ tsj_bot_user }}"
        group: "{{ tsj_bot_group }}"
        mode: "0640"
      loop:
        - { key: "AW_RUS_API_BASE", value: "{{ tsj_bot_aw_rus_api_base | default('http://192.0.2.13:5600/api/0') }}" }
        - { key: "AW_RUS_WORKTIME_BASE", value: "{{ tsj_bot_aw_rus_worktime_base | default('http://192.0.2.13:5610') }}" }
        - { key: "AW_DLP_POLICY_API_BASE", value: "{{ tsj_bot_aw_dlp_policy_api_base | default('http://192.0.2.13:5601/api/0') }}" }
        - { key: "AW_DLP_POLICY_ACTOR", value: "{{ tsj_bot_aw_dlp_policy_actor | default('tsj-guardian-bot') }}" }
        - { key: "AW_RUS_WORKTIME_HEAL_CMD", value: "{{ tsj_bot_aw_rus_worktime_heal_cmd | default(\"ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'sudo -n /usr/local/bin/aw-worktime-autoheal-rust && sudo -n systemctl reset-failed aw-worktime-ui-bridge.service && sudo -n systemctl start aw-worktime-ui-bridge.service'\") }}" }
        - { key: "AW_RUS_DLP_HEAL_CMD", value: "{{ tsj_bot_aw_rus_dlp_heal_cmd | default(\"ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'sudo -n systemctl restart activitywatch-server.service && (sudo -n systemctl start activitywatch-dlp-aggregator.service || true) && sudo -n /usr/local/bin/aw-health-check && sudo -n /usr/local/bin/dlp-health-check'\") }}" }
        - { key: "AW_RUS_CASE_API_BASE", value: "{{ tsj_bot_aw_rus_case_api_base | default('http://192.0.2.13:5602') }}" }
        - { key: "AW_RUS_HAYABUSA_ENABLED", value: "{{ tsj_bot_aw_rus_hayabusa_enabled | default('true') }}" }
        - { key: "AW_RUS_HAYABUSA_SSH_CMD", value: "{{ tsj_bot_aw_rus_hayabusa_ssh_cmd | default(\"ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13\") }}" }
        - { key: "AW_RUS_HOST", value: "{{ tsj_bot_aw_rus_host | default('HOST-EXAMPLE') }}" }
        - { key: "AW_RUS_PRIMARY_USER", value: "{{ tsj_bot_aw_rus_primary_user | default('USER1') }}" }
        - { key: "AW_RUS_STALE_SEC", value: "{{ tsj_bot_aw_rus_stale_sec | default(900) }}" }
        - { key: "AW_RUS_SLO_ENABLED", value: "{{ tsj_bot_aw_rus_slo_enabled | default('true') }}" }
        - { key: "AW_RUS_SLO_ALERT_WINDOW", value: "{{ tsj_bot_aw_rus_slo_alert_window | default('24h') }}" }
        - { key: "AW_RUS_SLO_MIN_SAMPLES", value: "{{ tsj_bot_aw_rus_slo_min_samples | default(4) }}" }
        - { key: "AW_RUS_SLO_MAX_AGE_SEC", value: "{{ tsj_bot_aw_rus_slo_max_age_sec | default(90) }}" }
        - { key: "AW_RUS_SLO_SUMMARY_CMD", value: "{{ tsj_bot_aw_rus_slo_summary_cmd | default(\"ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new igor@192.0.2.13 'cat /var/lib/activitywatch/slo/aw-slo-summary.json'\") }}" }
        - { key: "AW_RUS_WINDOWS_HOST", value: "{{ tsj_bot_aw_rus_windows_host | default(hostvars[(groups['aw_windows'] | first)].ansible_host | default('198.51.100.18')) }}" }
        - { key: "AW_RUS_WINDOWS_SSH_USER", value: "{{ tsj_bot_aw_rus_windows_ssh_user | default(hostvars[(groups['aw_windows'] | first)].ansible_user | default('Администратор')) }}" }
        - { key: "AW_RUS_WINDOWS_SSH_PASSWORD", value: "{{ tsj_bot_aw_rus_windows_ssh_password | default(hostvars[(groups['aw_windows'] | first)].ansible_password | default('')) }}" }
        - { key: "AW_RUS_WINDOWS_CONFIG_PATH", value: "{{ tsj_bot_aw_rus_windows_config_path | default('C:\\ProgramData\\AWatch-rus\\deployment-config.json') }}" }
        - { key: "AW_RUS_WINDOWS_HARDENING_RECOVERY_PATH", value: "{{ tsj_bot_aw_rus_windows_hardening_recovery_path | default('C:\\Program Files\\AWatch-rus\\windows\\hardening-recovery.ps1') }}" }
        - { key: "AW_RUS_WINDOWS_SESSION_COLLECTOR_PATH", value: "{{ tsj_bot_aw_rus_windows_session_collector_path | default('C:\\ProgramData\\AWatch-rus\\worktime-session-collector.ps1') }}" }
        - { key: "AW_RUS_WINDOWS_POLICY_PATH", value: "{{ tsj_bot_aw_rus_windows_policy_path | default('C:\\ProgramData\\AWatch-rus\\dlp-policy.json') }}" }
        - { key: "AW_RUS_WINDOWS_BROWSER_COLLECTOR_PATH", value: "{{ tsj_bot_aw_rus_windows_browser_collector_path | default('C:\\ProgramData\\AWatch-rus\\browser-domains-native-collector.ps1') }}" }
        - { key: "AW_RUS_WINDOWS_EMAIL_COLLECTOR_PATH", value: "{{ tsj_bot_aw_rus_windows_email_collector_path | default('C:\\ProgramData\\AWatch-rus\\email-outbound-collector.ps1') }}" }
        - { key: "AI_CHAT_WORKDIR", value: "{{ tsj_bot_ai_chat_workdir | default('~') }}" }
        - { key: "AI_EXEC_USER", value: "{{ tsj_bot_ai_exec_user | default('igor') }}" }
        - { key: "INCIDENT_FAILURE_QUORUM_CHECKS", value: "{{ tsj_bot_incident_failure_quorum_checks | default(2) }}" }
        - { key: "DETMIR_AI_STATE_FILE", value: "{{ tsj_bot_detmir_ai_state_file | default('/var/lib/detmir-ai/latest-state.json') }}" }
        - { key: "TSJ_GUARDIAN_STATUS_BIN", value: "{{ tsj_bot_guardian_status_bin | default('/usr/local/bin/tsj-guardian-status') }}" }
        - { key: "TMUX_USER", value: "{{ tsj_bot_tmux_user | default('igor') }}" }
        - { key: "PFSENSE_ENV_PATH", value: "{{ tsj_bot_pfsense_env_path | default('~/.config/tsj-bot/pfsense.env.readonly') }}" }
        - { key: "PFSENSE_INVENTORY_PATH", value: "{{ tsj_bot_pfsense_inventory_path | default('~/.config/tsj-bot/inventory.md') }}" }
      notify: Restart tsj bot

    - name: Установить systemd unit бота
      ansible.builtin.copy:
        dest: "/etc/systemd/system/{{ tsj_bot_service_name }}"
        owner: root
        group: root
        mode: "0644"
        content: |
          [Unit]
          Description=TSJ Guardian Telegram Bot
          After=network-online.target gost-tg.service anet-client.service pfsense-mcp-server.service
          Wants=network-online.target gost-tg.service anet-client.service pfsense-mcp-server.service

          [Service]
          Type=simple
          User=root
          WorkingDirectory={{ tsj_bot_runtime_root }}
          EnvironmentFile={{ tsj_bot_env_path }}
          ExecStart=/usr/bin/python3 {{ tsj_bot_script_dest }}
          Restart=always
          RestartSec=5
          KillMode=control-group

          [Install]
          WantedBy=multi-user.target
      notify:
        - Reload systemd
        - Restart tsj bot

    - name: Установить systemd unit watchdog бота
      ansible.builtin.copy:
        dest: "/etc/systemd/system/{{ tsj_bot_watchdog_service_name }}"
        owner: root
        group: root
        mode: "0644"
        content: |
          [Unit]
          Description=TSJ Guardian Bot Heartbeat Watchdog
          After={{ tsj_bot_service_name }} gost-tg.service
          Wants={{ tsj_bot_service_name }} gost-tg.service

          [Service]
          Type=simple
          User=root
          ExecStart=/bin/bash -lc 'while true; do {{ tsj_bot_watchdog_dest }}; sleep 60; done'
          StandardOutput=null
          StandardError=null
          Restart=always
          RestartSec=5

          [Install]
          WantedBy=multi-user.target
      notify:
        - Reload systemd
        - Restart tsj watchdog

    - name: Проверить синтаксис Python скрипта бота
      ansible.builtin.command: "python3 -m py_compile {{ tsj_bot_script_dest }}"
      changed_when: false

    - name: Включить и запустить сервис бота
      ansible.builtin.systemd:
        name: "{{ tsj_bot_service_name }}"
        enabled: true
        state: started

    - name: Включить и запустить watchdog бота
      ansible.builtin.systemd:
        name: "{{ tsj_bot_watchdog_service_name }}"
        enabled: true
        state: started

    - name: Проверить что сервис активен
      ansible.builtin.command: "systemctl is-active {{ tsj_bot_service_name }}"
      register: tsj_bot_active
      changed_when: false
      failed_when: tsj_bot_active.stdout.strip() != "active"

    - name: Проверить что watchdog активен
      ansible.builtin.command: "systemctl is-active {{ tsj_bot_watchdog_service_name }}"
      register: tsj_bot_watchdog_active
      changed_when: false
      failed_when: tsj_bot_watchdog_active.stdout.strip() != "active"

  handlers:
    - name: Reload systemd
      ansible.builtin.systemd:
        daemon_reload: true

    - name: Restart tsj bot
      ansible.builtin.systemd:
        name: "{{ tsj_bot_service_name }}"
        state: restarted

    - name: Restart tsj watchdog
      ansible.builtin.systemd:
        name: "{{ tsj_bot_watchdog_service_name }}"
        state: restarted
