package devopsmodules

import (
	"rubric/utils"
)

var CicdModule = Module{
	Key:         "cicd",
	Aliases:     []string{"ci", "cd", "pipeline"},
	Title:       "CI/CD — непрерывная интеграция и доставка",
	Description: "GitHub Actions, GitLab CI, Jenkins, принципы CI/CD",
	Run:         showCicd,
}

func showCicd() {
	utils.Header("DevOps — CI/CD")

	utils.Section("Принципы CI/CD")
	utils.Code(`CI (Continuous Integration) — непрерывная интеграция:
  - Разработчики часто коммитят в общую ветку
  - Автоматически запускаются: сборка, тесты, линтинг
  - Быстрая обратная связь (< 10 минут)

CD (Continuous Delivery) — непрерывная доставка:
  - Код всегда готов к деплою
  - Деплой в staging автоматически
  - В продакшн — одним кликом или автоматически

Типичный пайплайн:
  Коммит → Lint → Test → Build → Security scan → Deploy staging → Deploy prod

Метрики:
  Lead time     — время от коммита до продакшна
  Deploy freq   — частота деплоев
  MTTR          — среднее время восстановления
  Change fail % — процент неудачных деплоев`)

	utils.Section("GitHub Actions")
	utils.Code(`# .github/workflows/ci.yml
name: CI/CD

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: secret
        options: >-
          --health-cmd pg_isready
          --health-interval 10s

    steps:
    - uses: actions/checkout@v4

    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.22'
        cache: true

    - name: Run tests
      run: go test -v -race -coverprofile=coverage.out ./...

    - name: Upload coverage
      uses: codecov/codecov-action@v4

  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: golangci/golangci-lint-action@v4

  build-and-push:
    needs: [test, lint]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write

    steps:
    - uses: actions/checkout@v4

    - name: Log in to registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        push: true
        tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    environment: production   # требует ручного подтверждения

    steps:
    - name: Deploy to Kubernetes
      uses: azure/k8s-deploy@v4
      with:
        manifests: k8s/
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`)

	utils.Println(utils.ColorBold + "GitHub Actions — ключевые концепции:" + utils.ColorReset)
	utils.Code(`Workflow    — файл в .github/workflows/*.yml
Job         — набор шагов, запускается на runner
Step        — команда или action
Runner      — виртуальная машина (ubuntu/windows/macos)
Action      — переиспользуемый step (uses: actions/checkout@v4)
Secret      — зашифрованные переменные (Settings → Secrets)
Environment — защищённая среда с approval (production, staging)
Matrix      — параллельный запуск с разными параметрами:

strategy:
  matrix:
    go: ['1.21', '1.22']
    os: [ubuntu-latest, macos-latest]`)

	utils.Section("GitLab CI/CD")
	utils.Code(`# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

test:
  stage: test
  image: golang:1.22
  script:
    - go test ./...
    - go vet ./...
  coverage: '/coverage: \d+\.\d+%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE
  only:
    - main

deploy_staging:
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - main

deploy_prod:
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE
  environment:
    name: production
    url: https://example.com
  when: manual    # ручной запуск
  only:
    - main`)

	utils.Println(utils.ColorBold + "Встроенные переменные GitLab CI:" + utils.ColorReset)
	utils.Code(`CI_COMMIT_SHA          — полный SHA коммита
CI_COMMIT_SHORT_SHA    — короткий SHA
CI_COMMIT_BRANCH       — ветка
CI_COMMIT_TAG          — тег (если есть)
CI_REGISTRY            — адрес реестра (registry.gitlab.com)
CI_REGISTRY_IMAGE      — полный путь образа
CI_PROJECT_NAME        — имя проекта
CI_ENVIRONMENT_NAME    — имя окружения`)

	utils.Section("Jenkins")
	utils.Code(`// Jenkinsfile (Declarative Pipeline):
pipeline {
    agent any

    environment {
        DOCKER_CREDS = credentials('docker-hub')
        KUBECONFIG   = credentials('kubeconfig-prod')
    }

    stages {
        stage('Checkout') {
            steps { checkout scm }
        }

        stage('Test') {
            steps {
                sh 'go test ./...'
            }
            post {
                always {
                    junit 'test-results.xml'
                }
            }
        }

        stage('Build') {
            steps {
                sh """
                    docker build -t myapp:${env.BUILD_NUMBER} .
                    docker tag myapp:${env.BUILD_NUMBER} myrepo/myapp:latest
                """
            }
        }

        stage('Push') {
            steps {
                sh """
                    echo $DOCKER_CREDS_PSW | docker login -u $DOCKER_CREDS_USR --password-stdin
                    docker push myrepo/myapp:${env.BUILD_NUMBER}
                """
            }
        }

        stage('Deploy') {
            when { branch 'main' }
            steps {
                input message: 'Деплоить в продакшн?'
                sh "kubectl set image deployment/myapp myapp=myrepo/myapp:${env.BUILD_NUMBER}"
            }
        }
    }

    post {
        failure {
            slackSend channel: '#alerts', message: "FAILED: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
        success {
            slackSend channel: '#deployments', message: "DEPLOYED: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
    }
}`)

	utils.Section("ArgoCD — GitOps")
	utils.Code(`GitOps — Git как единственный источник истины для инфраструктуры.
ArgoCD наблюдает за Git-репозиторием и синхронизирует кластер.

# Установка:
kubectl create namespace argocd
kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# CLI:
argocd login argocd.example.com

# Создать приложение:
argocd app create myapp \
  --repo https://github.com/user/myapp \
  --path k8s/ \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace production \
  --sync-policy automated \
  --auto-prune

argocd app list
argocd app sync myapp
argocd app rollback myapp 3`)

	utils.Footer()
}
