name: Deploy to liderra.ru

# Запускается вручную через web-интерфейс GitHub или через `gh workflow run`.
# Решает проблему «дев-машина не достучится по SSH до прод-сервера через YC backbone»:
# GitHub Actions runner — внешний по отношению к YC, его IP не блокируется тем
# фильтром что блокирует мой dev-IP `89.144.17.119`.
#
# Требуемые secrets (Settings → Secrets and variables → Actions):
#   LIDERRA_SSH_KEY  — содержимое приватного ключа `~/.ssh/liderra_deploy`
#                       (начинается с `-----BEGIN OPENSSH PRIVATE KEY-----`).
# Host/user захардкожены — публичная информация, нет смысла в secrets.

on:
  workflow_dispatch:
    inputs:
      ref:
        description: 'Branch/tag/SHA для деплоя (по умолчанию main)'
        required: true
        default: 'main'
        type: string
      backfill_snapshot:
        description: 'Запустить snapshot:backfill за сегодня (default yes)'
        required: false
        default: true
        type: boolean

jobs:
  deploy:
    name: Deploy code + run redeploy.sh
    runs-on: ubuntu-latest
    timeout-minutes: 20
    concurrency:
      group: liderra-prod-deploy
      cancel-in-progress: false

    env:
      LIDERRA_HOST: 111.88.246.137
      LIDERRA_USER: ubuntu

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.ref }}

      - name: Setup Node 22
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: app/package-lock.json

      - name: Install frontend deps
        # --legacy-peer-deps: Histoire 1.0-beta.1 заявляет peerDep vite ^7,
        # установлено vite 8 — известный квирк проекта (memory feedback_environment.md #74).
        working-directory: app
        run: npm ci --legacy-peer-deps

      - name: Build frontend
        working-directory: app
        run: npm run build

      - name: Verify build artifacts present
        run: |
          test -f app/public/build/manifest.json
          ls app/public/build/assets/ | head -5
          du -sh app/public/build/

      - name: Create deploy tarball
        run: |
          tar czf /tmp/deploy.tgz \
            --exclude='app/.env' \
            --exclude='app/.env.example' \
            --exclude='app/.env.production' \
            --exclude='app/storage' \
            --exclude='app/vendor' \
            --exclude='app/node_modules' \
            --exclude='app/bootstrap/cache' \
            app db
          ls -lh /tmp/deploy.tgz

      - name: Setup SSH key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.LIDERRA_SSH_KEY }}" > ~/.ssh/liderra_deploy
          chmod 600 ~/.ssh/liderra_deploy
          ssh-keyscan -H ${{ env.LIDERRA_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: Upload tarball to prod
        run: |
          scp -i ~/.ssh/liderra_deploy -o StrictHostKeyChecking=accept-new \
            /tmp/deploy.tgz ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }}:/tmp/deploy.tgz

      - name: Pre-apply partitioned migrations via postgres superuser
        # Workaround for partitioned-table migrations:
        # 2026_05_27_120000_create_project_routing_snapshots_table.php has SET ROLE crm_migrator
        # which fails when pgsql connection = crm_app_user (not a member of crm_migrator),
        # poisoning the transaction. Established prod pattern (memory: paused_at migration 26.05):
        # apply schema via sudo -u postgres psql + insert into migrations table.
        # Idempotent — skips if already applied.
        run: |
          ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} 'bash -s' <<'REMOTE'
            set -euo pipefail
            MIG_NAME='2026_05_27_120000_create_project_routing_snapshots_table'

            ALREADY=$(sudo -u postgres psql -d liderra -tAc \
              "SELECT 1 FROM migrations WHERE migration = '${MIG_NAME}' LIMIT 1")
            if [ "${ALREADY}" = "1" ]; then
              echo "Migration ${MIG_NAME} already in migrations table — skipping."
              exit 0
            fi

            TABLE_EXISTS=$(sudo -u postgres psql -d liderra -tAc \
              "SELECT 1 FROM information_schema.tables WHERE table_name='project_routing_snapshots' LIMIT 1")

            if [ "${TABLE_EXISTS}" != "1" ]; then
              echo "Applying CREATE TABLE project_routing_snapshots via postgres superuser..."
              sudo -u postgres psql -d liderra -v ON_ERROR_STOP=1 <<'PSQL'
              BEGIN;
              CREATE TABLE project_routing_snapshots (
                  snapshot_date      DATE        NOT NULL,
                  project_id         BIGINT      NOT NULL,
                  tenant_id          BIGINT      NOT NULL,
                  daily_limit        INT         NOT NULL CHECK (daily_limit >= 0),
                  delivery_days_mask INT         NOT NULL CHECK (delivery_days_mask BETWEEN 0 AND 127),
                  regions            INT[]       NOT NULL DEFAULT '{}',
                  signal_type        TEXT        NOT NULL CHECK (signal_type IN ('call','site','sms')),
                  signal_identifier  TEXT,
                  sms_senders        JSONB,
                  sms_keyword        TEXT,
                  expected_volume    INT         NOT NULL CHECK (expected_volume >= 0),
                  delivered_count    INT         NOT NULL DEFAULT 0 CHECK (delivered_count >= 0),
                  created_at         TIMESTAMP   NOT NULL DEFAULT NOW(),
                  PRIMARY KEY (snapshot_date, project_id),
                  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
              ) PARTITION BY RANGE (snapshot_date);
              ALTER TABLE project_routing_snapshots OWNER TO crm_migrator;
              CREATE INDEX project_routing_snapshots_tenant_date_idx
                  ON project_routing_snapshots (tenant_id, snapshot_date);
              CREATE INDEX project_routing_snapshots_signal_idx
                  ON project_routing_snapshots (snapshot_date, signal_type, lower(signal_identifier));
              ALTER TABLE project_routing_snapshots ENABLE ROW LEVEL SECURITY;
              CREATE POLICY project_routing_snapshots_tenant_isolation
                  ON project_routing_snapshots
                  USING (tenant_id = current_setting('app.current_tenant_id', true)::bigint);
              GRANT SELECT, INSERT, UPDATE ON project_routing_snapshots TO crm_app_user;
              GRANT SELECT, INSERT, UPDATE, DELETE ON project_routing_snapshots TO crm_supplier_worker;
              CREATE TABLE project_routing_snapshots_y2026_m05
                  PARTITION OF project_routing_snapshots
                  FOR VALUES FROM ('2026-05-01') TO ('2026-06-01');
              CREATE TABLE project_routing_snapshots_y2026_m06
                  PARTITION OF project_routing_snapshots
                  FOR VALUES FROM ('2026-06-01') TO ('2026-07-01');
              ALTER TABLE project_routing_snapshots_y2026_m05 OWNER TO crm_migrator;
              ALTER TABLE project_routing_snapshots_y2026_m06 OWNER TO crm_migrator;
              INSERT INTO system_settings (key, value, type, description, updated_at)
                  VALUES ('partition_retention_months_project_routing_snapshots', '3', 'int',
                          'Retention в месяцах для project_routing_snapshots (90 дней)', NOW())
                  ON CONFLICT (key) DO NOTHING;
              COMMIT;
          PSQL
            else
              echo "Table project_routing_snapshots already exists but migration not marked — marking only."
            fi

            # Mark migration as applied so Laravel migrate skips it.
            # Laravel's migrations table has no UNIQUE on `migration` column, so
            # ON CONFLICT doesn't work — use INSERT...SELECT WHERE NOT EXISTS for idempotency.
            NEXT_BATCH=$(sudo -u postgres psql -d liderra -tAc "SELECT COALESCE(MAX(batch),0)+1 FROM migrations")
            sudo -u postgres psql -d liderra -c \
              "INSERT INTO migrations (migration, batch) SELECT '${MIG_NAME}', ${NEXT_BATCH} WHERE NOT EXISTS (SELECT 1 FROM migrations WHERE migration='${MIG_NAME}');"
            echo "Marked ${MIG_NAME} as applied (batch ${NEXT_BATCH})"
          REMOTE

      - name: Extract + run redeploy.sh on prod
        run: |
          ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} 'bash -s' <<'REMOTE'
            set -euo pipefail
            TS=$(date -u +%Y%m%d-%H%M%S)
            echo "=== Backup current app ==="
            sudo tar czf /home/ubuntu/deploy-backups/app-pre-deploy-${TS}.tgz \
              --exclude='storage' --exclude='vendor' --exclude='node_modules' --exclude='public/build' \
              -C /var/www/liderra app
            ls -lh /home/ubuntu/deploy-backups/app-pre-deploy-${TS}.tgz

            echo "=== Extract overlay ==="
            cd /var/www/liderra
            sudo tar xzf /tmp/deploy.tgz
            sudo chown -R www-data:www-data /var/www/liderra/app /var/www/liderra/db

            echo "=== redeploy.sh (composer + migrate + optimize + restart) ==="
            sudo bash /var/www/liderra/redeploy.sh

            rm -f /tmp/deploy.tgz
          REMOTE

      - name: Backfill today's snapshot
        if: ${{ github.event.inputs.backfill_snapshot != 'false' }}
        run: |
          ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} 'bash -s' <<'REMOTE'
            set -e
            cd /var/www/liderra/app
            sudo -u www-data php artisan snapshot:backfill --date=$(date +%Y-%m-%d) || \
              echo "WARN: backfill returned non-zero — проверь вручную"
          REMOTE

      - name: Smoke tests
        run: |
          ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} 'bash -s' <<'REMOTE'
            set -e
            cd /var/www/liderra/app
            echo '=== Migrations status (last 5) ==='
            sudo -u www-data php artisan migrate:status 2>&1 | tail -5
            echo '=== Snapshots count (last 3 dates) ==='
            sudo -u postgres psql -d liderra -c "SELECT snapshot_date, COUNT(*) AS rows FROM project_routing_snapshots GROUP BY 1 ORDER BY 1 DESC LIMIT 3;" || true
            echo '=== Service status ==='
            systemctl is-active nginx php8.3-fpm postgresql liderra-queue
            echo '=== Internal portal health ==='
            curl -sf -o /dev/null -w 'https=%{http_code} time=%{time_total}s\n' --max-time 8 https://127.0.0.1/ -k || true
          REMOTE

      - name: External portal health (from runner)
        run: |
          curl -sf -o /dev/null -w 'external https=%{http_code} time=%{time_total}s\n' \
            --max-time 15 https://liderra.ru/ || echo "external health returned non-zero"

      - name: Cleanup SSH key
        if: always()
        run: rm -f ~/.ssh/liderra_deploy
