use colored::Colorize;
use lmrc_config_validator::LmrcConfig;
use std::fs;
use std::path::Path;

use crate::error::Result;

pub fn generate_docs(project_path: &Path, config: &LmrcConfig) -> Result<()> {
    let docs_path = project_path.join("docs");

    // Generate README.md
    generate_readme(&docs_path, config)?;

    // Generate SECRETS.md with required GitLab variables
    generate_secrets_doc(&docs_path, config)?;

    // Generate SETUP.md with setup instructions
    generate_setup_doc(&docs_path, config)?;

    println!("  {} docs/", "Created:".green());

    Ok(())
}

fn generate_readme(docs_path: &Path, config: &LmrcConfig) -> Result<()> {
    let readme = format!(
        r#"# {}

{}

## Project Structure

```
.
├── apps/          # Application code
├── libs/          # Shared libraries
├── infra/         # Infrastructure code
│   └── pipeline/  # Deployment pipeline binary
├── docker/        # Docker configurations
├── docs/          # Documentation
└── lmrc.toml      # Project configuration
```

## Applications

{}

## Quick Start

### Prerequisites

- Rust 1.75 or later
- Docker and docker-compose
- Access to configured cloud providers

### Local Development

1. Start local services:
   ```bash
   cd docker
   docker-compose up -d
   ```

2. Build the project:
   ```bash
   cargo build
   ```

3. Run an application:
   ```bash
   cargo run -p <app-name>
   ```

### Pipeline Commands

Build the pipeline binary:
```bash
cd infra/pipeline
cargo build --release
```

Run pipeline commands:
```bash
# Show configuration
./target/release/pipeline config

# Provision infrastructure
./target/release/pipeline provision

# Setup services (K8s, databases, etc.)
./target/release/pipeline setup

# Deploy applications
./target/release/pipeline deploy

# Run full pipeline
./target/release/pipeline full
```

## Infrastructure Stack

- **Server Provider**: {}
- **Kubernetes**: {}
- **Database**: {}
- **DNS**: {}
- **CI/CD**: {}

## Configuration

The project configuration is stored in `lmrc.toml`. See the file for all available options.

## GitLab CI/CD

The project includes a `.gitlab-ci.yml` file that:
1. Builds the pipeline binary
2. Builds and tests all applications
3. Provisions infrastructure (manual trigger)
4. Sets up services
5. Deploys applications

### Required GitLab Variables

See [SECRETS.md](./SECRETS.md) for the complete list of required CI/CD variables.

## Documentation

- [SECRETS.md](./SECRETS.md) - Required secrets and GitLab variables
- [SETUP.md](./SETUP.md) - Detailed setup instructions

## License

Apache-2.0
"#,
        config.project.name,
        config.project.description,
        config
            .apps
            .applications
            .iter()
            .map(|app| format!("- **{}**: {} application", app.name, app.app_type))
            .collect::<Vec<_>>()
            .join("\n"),
        config.providers.server,
        config.providers.kubernetes,
        config.providers.database,
        config.providers.dns,
        config.providers.git
    );

    fs::write(docs_path.join("README.md"), readme)?;

    Ok(())
}

fn generate_secrets_doc(docs_path: &Path, config: &LmrcConfig) -> Result<()> {
    let mut secrets = vec![
        "# Required Secrets and Variables\n".to_string(),
        "This document lists all required secrets and CI/CD variables that must be configured in GitLab.\n".to_string(),
        "## GitLab Configuration\n".to_string(),
        format!(
            "Navigate to: `{}/{} > Settings > CI/CD > Variables`\n",
            config
                .infrastructure
                .gitlab
                .as_ref()
                .map(|g| g.url.as_str())
                .unwrap_or("https://gitlab.com"),
            config.project.name
        ),
    ];

    // Server provider secrets
    if config.providers.server == "hetzner" {
        secrets.push("\n## Hetzner Cloud\n".to_string());
        secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
        secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
        secrets.push(
            "| `HETZNER_API_TOKEN` | Variable | Hetzner Cloud API token | Yes | Yes |\n"
                .to_string(),
        );
        secrets.push("\n**How to get:**\n".to_string());
        secrets.push("1. Log in to Hetzner Cloud Console\n".to_string());
        secrets.push("2. Go to your project\n".to_string());
        secrets.push("3. Navigate to Security > API Tokens\n".to_string());
        secrets.push("4. Generate a new token with Read & Write permissions\n".to_string());
    }

    // Database secrets
    if config.providers.database == "postgres" {
        secrets.push("\n## PostgreSQL\n".to_string());
        secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
        secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
        secrets.push(
            "| `POSTGRES_PASSWORD` | Variable | PostgreSQL admin password | Yes | Yes |\n"
                .to_string(),
        );
        secrets.push(
            "| `DATABASE_URL` | Variable | Database connection string | Yes | Yes |\n".to_string(),
        );
    }

    // DNS provider secrets
    if config.providers.dns == "cloudflare" {
        secrets.push("\n## Cloudflare\n".to_string());
        secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
        secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
        secrets.push(
            "| `CLOUDFLARE_API_TOKEN` | Variable | Cloudflare API token | Yes | Yes |\n"
                .to_string(),
        );
        secrets.push(
            "| `CLOUDFLARE_ZONE_ID` | Variable | Cloudflare Zone ID | No | No |\n".to_string(),
        );
        secrets.push("\n**How to get:**\n".to_string());
        secrets.push("1. Log in to Cloudflare Dashboard\n".to_string());
        secrets.push("2. Go to My Profile > API Tokens\n".to_string());
        secrets.push("3. Create token with Zone:DNS:Edit permissions\n".to_string());
        secrets.push("4. Get Zone ID from your domain's Overview page\n".to_string());
    }

    // Kubernetes secrets
    if config.providers.kubernetes == "k3s" {
        secrets.push(format!("\n## {} Cluster\n", config.providers.kubernetes));
        secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
        secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
        secrets.push("| `KUBECONFIG` | File | Kubernetes config file | Yes | No |\n".to_string());
        secrets
            .push("| `K8S_NAMESPACE` | Variable | Kubernetes namespace | No | No |\n".to_string());
    }

    // SSH access
    secrets.push("\n## SSH Access\n".to_string());
    secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
    secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
    secrets.push(
        "| `SSH_PRIVATE_KEY` | File | SSH private key for server access | Yes | Yes |\n"
            .to_string(),
    );
    secrets.push("| `SSH_KNOWN_HOSTS` | File | SSH known hosts file | No | No |\n".to_string());

    // Container registry
    secrets.push("\n## Container Registry\n".to_string());
    secrets.push("| Variable Name | Type | Description | Protected | Masked |\n".to_string());
    secrets.push("|---------------|------|-------------|-----------|--------|\n".to_string());
    secrets.push(
        "| `CI_REGISTRY_USER` | Variable | Container registry username | No | No |\n".to_string(),
    );
    secrets.push(
        "| `CI_REGISTRY_PASSWORD` | Variable | Container registry password | Yes | Yes |\n"
            .to_string(),
    );
    secrets.push("\n**Note:** GitLab provides built-in registry variables. Use them if using GitLab Container Registry.\n".to_string());

    // Summary
    secrets.push("\n## Quick Setup Script\n".to_string());
    secrets.push("You can use the GitLab API to set variables programmatically:\n\n".to_string());
    secrets.push("```bash\n".to_string());
    secrets.push("#!/bin/bash\n".to_string());
    secrets.push("GITLAB_TOKEN=\"your-gitlab-token\"\n".to_string());
    secrets.push(format!("PROJECT_ID=\"{}\"\n", config.project.name));
    secrets.push(format!(
        "GITLAB_URL=\"{}\"\n\n",
        config
            .infrastructure
            .gitlab
            .as_ref()
            .map(|g| g.url.as_str())
            .unwrap_or("https://gitlab.com")
    ));
    secrets.push("# Example: Set Hetzner API token\n".to_string());
    secrets.push("curl --request POST --header \"PRIVATE-TOKEN: $GITLAB_TOKEN\" \\\n".to_string());
    secrets.push("  \"$GITLAB_URL/api/v4/projects/$PROJECT_ID/variables\" \\\n".to_string());
    secrets.push("  --form \"key=HETZNER_API_TOKEN\" \\\n".to_string());
    secrets.push("  --form \"value=your-token-here\" \\\n".to_string());
    secrets.push("  --form \"protected=true\" \\\n".to_string());
    secrets.push("  --form \"masked=true\"\n".to_string());
    secrets.push("```\n".to_string());

    fs::write(docs_path.join("SECRETS.md"), secrets.join(""))?;

    Ok(())
}

fn generate_setup_doc(docs_path: &Path, config: &LmrcConfig) -> Result<()> {
    let setup = format!(
        r#"# Setup Guide

This guide walks you through setting up the {} infrastructure project.

## Prerequisites

### Development Machine

- Rust 1.75 or later
- Docker and docker-compose
- Git
- kubectl (for Kubernetes management)

### Cloud Accounts

{}

## Step 1: Clone and Configure

1. Clone the repository:
   ```bash
   git clone <repository-url>
   cd {}
   ```

2. Review and update `lmrc.toml` if needed

3. Verify the configuration:
   ```bash
   cd infra/pipeline
   cargo run -- config
   ```

## Step 2: Configure GitLab CI/CD Variables

Follow the instructions in [SECRETS.md](./SECRETS.md) to configure all required secrets and variables in GitLab.

## Step 3: Local Development Setup

1. Start local services:
   ```bash
   cd docker
   docker-compose up -d
   ```

2. Build all applications:
   ```bash
   cargo build
   ```

3. Run tests:
   ```bash
   cargo test
   ```

## Step 4: Infrastructure Provisioning

### Option A: Using GitLab CI/CD (Recommended)

1. Push your code to GitLab
2. Go to CI/CD > Pipelines
3. Manually trigger the `provision` job
4. The pipeline will automatically run setup and deploy after provisioning

### Option B: Manual Provisioning

1. Build the pipeline binary:
   ```bash
   cd infra/pipeline
   cargo build --release
   ```

2. Run provisioning:
   ```bash
   ./target/release/pipeline provision
   ```

3. Run setup:
   ```bash
   ./target/release/pipeline setup
   ```

4. Deploy applications:
   ```bash
   ./target/release/pipeline deploy
   ```

## Step 5: Verify Deployment

{}

## Troubleshooting

### Pipeline fails to build
- Check that all required GitLab variables are set
- Verify Rust version is 1.75 or later

### Provisioning fails
- Verify cloud provider credentials are correct
- Check that your account has sufficient permissions
- Review the logs for specific error messages

### Deployment fails
- Ensure Kubernetes cluster is accessible
- Verify kubeconfig is correctly configured
- Check that Docker images built successfully

## Next Steps

- Set up monitoring and logging
- Configure backups
- Set up alerting
- Review security settings

## Support

For issues and questions, please refer to the project documentation or create an issue in the repository.
"#,
        config.project.name,
        generate_cloud_accounts_section(config),
        config.project.name,
        generate_verification_section(config)
    );

    fs::write(docs_path.join("SETUP.md"), setup)?;

    Ok(())
}

fn generate_cloud_accounts_section(config: &LmrcConfig) -> String {
    let mut accounts = Vec::new();

    if config.providers.server == "hetzner" {
        accounts.push("- Hetzner Cloud account with billing enabled");
    }

    if config.providers.dns == "cloudflare" {
        accounts.push("- Cloudflare account with domain registered");
    }

    if config.providers.git == "gitlab" {
        accounts.push("- GitLab account with project created");
    }

    accounts.join("\n")
}

fn generate_verification_section(config: &LmrcConfig) -> String {
    let mut checks = Vec::new();

    if config.providers.kubernetes == "k3s" || config.providers.kubernetes == "kubernetes" {
        checks.push(
            r#"1. Check cluster status:
   ```bash
   kubectl get nodes
   kubectl get pods --all-namespaces
   ```
"#,
        );
    }

    if config.providers.database == "postgres" {
        checks.push(
            r#"2. Verify database connection:
   ```bash
   psql $DATABASE_URL -c "SELECT version();"
   ```
"#,
        );
    }

    checks.push(
        r#"3. Check application endpoints:
   ```bash
   curl https://your-domain.com/health
   ```
"#,
    );

    checks.join("\n")
}
