# === DOCKERFILE (API Server) ===
FROM python:3.9-slim-buster

WORKDIR /app

# Copy requirements file
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 5000

# Define environment variables (example)
ENV FLASK_APP=app.py
ENV FLASK_ENV=production

# Command to run the application
CMD ["flask", "run", "--host=0.0.0.0"]

# === DOCKER-COMPOSE.YML (Local Development) ===
version: "3.9"
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "5000:5000"
    environment:
      FLASK_APP: app.py
      FLASK_ENV: development
      DATABASE_URL: postgresql://genesis_user:genesis_password@db:5432/genesis_db
      REDIS_URL: redis://redis:6379/0
      MESSAGE_QUEUE_URL: amqp://guest:guest@rabbitmq:5672//
    depends_on:
      - db
      - redis
      - rabbitmq
    volumes:
      - .:/app
  db:
    image: postgres:14
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: genesis_user
      POSTGRES_PASSWORD: genesis_password
      POSTGRES_DB: genesis_db
    volumes:
      - db_data:/var/lib/postgresql/data
  redis:
    image: redis:7
    ports:
      - "6379:6379"
  rabbitmq:
    image: rabbitmq:3-management
    ports:
      - "5672:5672"
      - "15672:15672" # Management UI

volumes:
  db_data:

# === DOCKER-COMPOSE.PROD.YML (Production) ===
version: "3.9"
services:
  api:
    image: your-dockerhub-username/genesis-api:latest # Replace with your image
    ports:
      - "80:5000" # Map host port 80 to container port 5000
    environment:
      FLASK_APP: app.py
      FLASK_ENV: production
      DATABASE_URL: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}
      REDIS_URL: redis://${REDIS_HOST}:${REDIS_PORT}/0
      MESSAGE_QUEUE_URL: amqp://${MESSAGE_QUEUE_USER}:${MESSAGE_QUEUE_PASSWORD}@${MESSAGE_QUEUE_HOST}:${MESSAGE_QUEUE_PORT}//
    depends_on:
      - db
      - redis
      - rabbitmq
    deploy:
      replicas: 3 # Scale up to 3 replicas
      restart_policy:
        condition: on-failure # Restart on failure
  db:
    image: postgres:14
    environment:
      POSTGRES_USER: ${DATABASE_USER}
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
      POSTGRES_DB: ${DATABASE_NAME}
    volumes:
      - db_data:/var/lib/postgresql/data # Persist data even after container removal
    deploy:
      restart_policy:
        condition: on-failure
  redis:
    image: redis:7
    deploy:
      restart_policy:
        condition: on-failure
  rabbitmq:
    image: rabbitmq:3-management
    environment:
      RABBITMQ_DEFAULT_USER: ${MESSAGE_QUEUE_USER}
      RABBITMQ_DEFAULT_PASS: ${MESSAGE_QUEUE_PASSWORD}
    deploy:
      restart_policy:
        condition: on-failure

volumes:
  db_data:

# === K8S-DEPLOYMENT.YAML (API Deployment) ===
apiVersion: apps/v1
kind: Deployment
metadata:
  name: genesis-api-deployment
  labels:
    app: genesis-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: genesis-api
  template:
    metadata:
      labels:
        app: genesis-api
    spec:
      containers:
      - name: genesis-api
        image: your-dockerhub-username/genesis-api:latest # Replace with your image
        ports:
        - containerPort: 5000
        env:
        - name: FLASK_APP
          value: app.py
        - name: FLASK_ENV
          value: production
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: genesis-db-credentials
              key: database_url
        - name: REDIS_URL
          valueFrom:
            secretKeyRef:
              name: genesis-redis-credentials
              key: redis_url
        - name: MESSAGE_QUEUE_URL
          valueFrom:
            secretKeyRef:
              name: genesis-rabbitmq-credentials
              key: message_queue_url
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "500m"
            memory: "1Gi"

# === K8S-SERVICE.YAML (API Service) ===
apiVersion: v1
kind: Service
metadata:
  name: genesis-api-service
spec:
  selector:
    app: genesis-api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000
  type: LoadBalancer # Use ClusterIP if behind an Ingress

# === K8S-CONFIGMAP.YAML (Example Config) ===
apiVersion: v1
kind: ConfigMap
metadata:
  name: genesis-config
data:
  example_setting: "some_value"

# === K8S-SECRET.YAML (Database Credentials) ===
apiVersion: v1
kind: Secret
metadata:
  name: genesis-db-credentials
type: Opaque
data:
  database_url: <BASE64_ENCODED_DATABASE_URL> # e.g., postgresql://user:password@host:port/db
  # Use `echo -n "your_database_url" | base64` to encode

# === K8S-SECRET.YAML (Redis Credentials) ===
apiVersion: v1
kind: Secret
metadata:
  name: genesis-redis-credentials
type: Opaque
data:
  redis_url: <BASE64_ENCODED_REDIS_URL> # e.g., redis://host:port/0

# === K8S-SECRET.YAML (RabbitMQ Credentials) ===
apiVersion: v1
kind: Secret
metadata:
  name: genesis-rabbitmq-credentials
type: Opaque
data:
  message_queue_url: <BASE64_ENCODED_RABBITMQ_URL> # e.g., amqp://user:password@host:port//

# === K8S-HPA.YAML (Horizontal Pod Autoscaler) ===
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: genesis-api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: genesis-api-deployment
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

# === K8S-INGRESS.YAML (Ingress Configuration) ===
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: genesis-ingress
  annotations:
    kubernetes.io/ingress.class: nginx # Or your ingress controller
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: genesis.example.com # Replace with your domain
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: genesis-api-service
            port:
              number: 80

# === TERRAFORM (Cloud Resources) ===
# main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
  required_version = ">= 0.14.0"
}

provider "aws" {
  region = "us-east-1" # Replace with your desired region
}

# VPC
resource "aws_vpc" "genesis_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "genesis-vpc"
  }
}

# Subnets (Public and Private)
resource "aws_subnet" "public_subnet_a" {
  vpc_id     = aws_vpc.genesis_vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true
  tags = {
    Name = "genesis-public-subnet-a"
  }
}

resource "aws_subnet" "private_subnet_a" {
  vpc_id     = aws_vpc.genesis_vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "us-east-1a"
  tags = {
    Name = "genesis-private-subnet-a"
  }
}

# Internet Gateway
resource "aws_internet_gateway" "genesis_igw" {
  vpc_id = aws_vpc.genesis_vpc.id
  tags = {
    Name = "genesis-internet-gateway"
  }
}

# Route Table (Public)
resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.genesis_vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.genesis_igw.id
  }
  tags = {
    Name = "genesis-public-route-table"
  }
}

# Route Table Association (Public Subnet)
resource "aws_route_table_association" "public_subnet_association" {
  subnet_id      = aws_subnet.public_subnet_a.id
  route_table_id = aws_route_table.public_route_table.id
}

# Security Group (Allow HTTP/HTTPS/SSH)
resource "aws_security_group" "genesis_sg" {
  name        = "genesis-security-group"
  description = "Allow HTTP, HTTPS, and SSH traffic"
  vpc_id      = aws_vpc.genesis_vpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # Restrict to your IP address in production
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "genesis-security-group"
  }
}


# Elastic Container Registry (ECR)
resource "aws_ecr_repository" "genesis_api_ecr" {
  name = "genesis-api"
  tags = {
    Name = "genesis-api-ecr"
  }
}

output "ecr_repository_url" {
  value = aws_ecr_repository.genesis_api_ecr.repository_url
}

# RDS PostgreSQL Database
resource "aws_db_instance" "genesis_db" {
  allocated_storage    = 20 # GB
  engine               = "postgres"
  engine_version       = "14.6"
  instance_class       = "db.t3.micro"
  name                 = "genesis_db"
  username             = "genesis_user"
  password             = "genesis_password" # Store in a secure way (Secrets Manager)
  db_subnet_group_name = aws_db_subnet_group.genesis_db_subnet_group.name
  vpc_security_group_ids = [aws_security_group.genesis_sg.id]
  publicly_accessible = false
  skip_final_snapshot = true # For demo purposes only.  Remove in production.
  multi_az             = false

  tags = {
    Name = "genesis-db"
  }
}

resource "aws_db_subnet_group" "genesis_db_subnet_group" {
  name       = "genesis-db-subnet-group"
  subnet_ids = [aws_subnet.private_subnet_a.id]

  tags = {
    Name = "genesis-db-subnet-group"
  }
}

output "db_endpoint" {
  value = aws_db_instance.genesis_db.endpoint
  sensitive = true # Important as it contains the DB address
}

# Elasticache Redis
resource "aws_elasticache_cluster" "genesis_redis" {
  cluster_id           = "genesis-redis"
  engine               = "redis"
  node_type            = "cache.t3.micro"
  num_cache_nodes      = 1
  port                 = 6379
  subnet_group_name = aws_elasticache_subnet_group.genesis_redis_subnet_group.name
  security_group_ids = [aws_security_group.genesis_sg.id]

  tags = {
    Name = "genesis-redis"
  }
}

resource "aws_elasticache_subnet_group" "genesis_redis_subnet_group" {
  name       = "genesis-redis-subnet-group"
  subnet_ids = [aws_subnet.private_subnet_a.id]
}

output "redis_endpoint" {
  value = aws_elasticache_cluster.genesis_redis.cache_nodes[0].address
  sensitive = true
}

# SQS Message Queue (Example)
resource "aws_sqs_queue" "genesis_queue" {
  name = "genesis-queue"
  visibility_timeout_seconds = 30

  tags = {
    Name = "genesis-queue"
  }
}

output "sqs_queue_url" {
  value = aws_sqs_queue.genesis_queue.id
}

# === CI/CD (GitHub Actions Workflow) ===
# .github/workflows/main.yml
name: CI/CD Pipeline

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python 3.9
        uses: actions/setup-python@v3
        with:
          python-version: 3.9
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run Tests
        run: pytest # Assuming you use pytest

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: genesis-api
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Update K8s deployment
        run: |
          # Replace the image tag in the deployment file
          sed -i "s|your-dockerhub-username/genesis-api:latest|${{ needs.build.outputs.image }}|g" K8S-DEPLOYMENT.YAML
          # Apply the updated deployment file
          kubectl apply -f K8S-DEPLOYMENT.YAML
        env:
          KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA }} # Store your kubeconfig as a secret
      - name: Deploy to Kubernetes Cluster
        uses: azure/k8s-deploy@v1
        with:
          namespace: default
          manifests: K8S-DEPLOYMENT.YAML # Assuming you have a deployment.yaml file
          kubeconfig: ${{ secrets.KUBE_CONFIG_DATA }}
          images: ${{ needs.build.outputs.image }}

  security_scan:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ needs.build.outputs.image }}
          format: 'table'
          exit-code: '1'
          ignore-unfixed: true
          severity: 'CRITICAL,HIGH'

  release:
    needs: [deploy, security_scan]
    runs-on: ubuntu-latest
    steps:
      - name: Create Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: v${{ github.run_number }}
          release_name: Release v${{ github.run_number }}
          body: |
            Automated release based on commit ${{ github.sha }}
          draft: false
          prerelease: false

# === MONITORING (Prometheus, Grafana, PagerDuty) ===

# --- Prometheus ---
# prometheus.yml (scrape_configs)
scrape_configs:
  - job_name: 'genesis-api'
    metrics_path: '/metrics' # Assuming your API exposes a /metrics endpoint
    static_configs:
      - targets: ['genesis-api-service:5000'] # Use the service name and port

  - job_name: 'kubernetes-cadvisor'
    scrape_interval: 5s
    static_configs:
      - targets:
        - kubelet:10250 # Replace kubelet with appropriate dns
        labels:
          job: cadvisor

  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: pod

# --- Grafana ---
# grafana_dashboard.json (Example Dashboard)
#  (This is a large JSON object, so providing a complete example is difficult in this format.  I will provide a structure and key components)

{
  "annotations": {
    "list": []
  },
  "description": "Dashboard for Genesis Patent System API",
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": null,
  "links": [],
  "panels": [
    {
      "datasource": "Prometheus",
      "fieldConfig": {
        "defaults": {
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "id": 1,
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "showCommonLabels": false,
          "showLegend": true
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "targets": [
        {
          "expr": "rate(http_requests_total[5m])", # Example: HTTP request rate
          "legendFormat": "{{method}} {{path}}",
          "refId": "A"
        }
      ],
      "title": "HTTP Request Rate",
      "type": "timeseries"
    },
    {
      "datasource": "Prometheus",
      "fieldConfig": {
        "defaults": {
          "unit": "percent"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "id": 2,
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "showCommonLabels": false,
          "showLegend": true
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "targets": [
        {
          "expr": "sum(rate(process_cpu_seconds_total[5m])) by (instance)", # Example: CPU Usage
          "legendFormat": "{{instance}}",
          "refId": "A"
        }
      ],
      "title": "CPU Usage",
      "type": "timeseries"
    }
  ],
  "schemaVersion": 30,
  "style": "dark",
  "tags": [
    "genesis",
    "api"
  ],
  "templating": {
    "list": []
  },
  "time": {
    "from": "now-6h",
    "to": "now"
  },
  "timepicker": {
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ]
  },
  "timezone": "",
  "title": "Genesis API Dashboard",
  "uid": "your_dashboard_uid",
  "version": 1
}

# Key Panel Types:
# - timeseries: For displaying metrics over time.
# - stat: For displaying a single value.
# - gauge: For displaying a current value.
# - table: For displaying data in a tabular format.

# --- Prometheus Alert Rules ---
# alert.rules.yml
groups:
- name: GenesisAPIAlerts
  rules:
  - alert: APIHighRequestLatency
    expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) > 1 # Example: 99th percentile latency > 1 second
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "API request latency is high"
      description: "API request latency is above 1 second (99th percentile) for 5 minutes.  Instance: {{ $labels.instance }}"

  - alert: APIHighCPUUsage
    expr: sum(rate(process_cpu_seconds_total[5m])) by (instance) > 0.8 # Example: CPU usage > 80%
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "API CPU usage is high"
      description: "API CPU usage is above 80% for 5 minutes. Instance: {{ $labels.instance }}"

# --- PagerDuty Integration ---

# 1. Create a PagerDuty integration service.
# 2. Get the integration key from PagerDuty.
# 3. Configure Prometheus to send alerts to PagerDuty using the integration key.

# Example Prometheus configuration (in prometheus.yml):
# alertmanager_config:
#   global:
#     resolve_timeout: 5m
#   route:
#     group_wait: 30s
#     group_interval: 5m
#     repeat_interval: 1h
#     receiver: 'pagerduty'
#   receivers:
#   - name: 'pagerduty'
#     pagerduty_configs:
#     - service_key: 'YOUR_PAGERDUTY_INTEGRATION_KEY'
#       send_resolved: true

# Remember to replace 'YOUR_PAGERDUTY_INTEGRATION_KEY' with your actual PagerDuty integration key.
