"""add script templates

Revision ID: 057
Revises: 056
Create Date: 2026-03-12
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID, JSONB, ENUM as PG_ENUM
import uuid
import json
from datetime import datetime, timezone

revision = "057"
down_revision = "056"
branch_labels = None
depends_on = None


def upgrade() -> None:
    # ── Create enum ──────────────────────────────────────────────────────
    op.execute("CREATE TYPE script_complexity AS ENUM ('beginner', 'intermediate', 'advanced')")

    # ── script_categories ────────────────────────────────────────────────
    op.create_table(
        "script_categories",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("name", sa.String(100), nullable=False),
        sa.Column("slug", sa.String(100), nullable=False, unique=True),
        sa.Column("description", sa.Text, nullable=True),
        sa.Column("icon", sa.String(50), nullable=True),
        sa.Column("sort_order", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("is_active", sa.Boolean, nullable=False, server_default=sa.text("true")),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
    )
    op.create_index("ix_script_categories_slug", "script_categories", ["slug"])

    # ── script_templates ─────────────────────────────────────────────────
    op.create_table(
        "script_templates",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("category_id", UUID(as_uuid=True), sa.ForeignKey("script_categories.id", ondelete="RESTRICT"), nullable=False),
        sa.Column("team_id", UUID(as_uuid=True), sa.ForeignKey("teams.id", ondelete="CASCADE"), nullable=True),
        sa.Column("created_by", UUID(as_uuid=True), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True),
        sa.Column("name", sa.String(200), nullable=False),
        sa.Column("slug", sa.String(200), nullable=False),
        sa.Column("description", sa.Text, nullable=True),
        sa.Column("use_case", sa.Text, nullable=True),
        sa.Column("script_body", sa.Text, nullable=False),
        sa.Column("parameters_schema", JSONB, nullable=False, server_default=sa.text("'{}'::jsonb")),
        sa.Column("default_values", JSONB, nullable=False, server_default=sa.text("'{}'::jsonb")),
        sa.Column("validation_rules", JSONB, nullable=False, server_default=sa.text("'{}'::jsonb")),
        sa.Column("tags", JSONB, nullable=False, server_default=sa.text("'[]'::jsonb")),
        sa.Column("complexity", PG_ENUM("beginner", "intermediate", "advanced", name="script_complexity", create_type=False), nullable=False, server_default=sa.text("'beginner'")),
        sa.Column("estimated_runtime", sa.String(50), nullable=True),
        sa.Column("requires_elevation", sa.Boolean, nullable=False, server_default=sa.text("true")),
        sa.Column("requires_modules", JSONB, nullable=False, server_default=sa.text("'[]'::jsonb")),
        sa.Column("version", sa.Integer, nullable=False, server_default=sa.text("1")),
        sa.Column("is_verified", sa.Boolean, nullable=False, server_default=sa.text("false")),
        sa.Column("is_active", sa.Boolean, nullable=False, server_default=sa.text("true")),
        sa.Column("usage_count", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
    )
    op.create_index("ix_script_templates_category_id", "script_templates", ["category_id"])
    op.create_index("ix_script_templates_team_id", "script_templates", ["team_id"])
    op.create_index("ix_script_templates_slug", "script_templates", ["slug"])

    # ── script_generations ───────────────────────────────────────────────
    op.create_table(
        "script_generations",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("template_id", UUID(as_uuid=True), sa.ForeignKey("script_templates.id", ondelete="RESTRICT"), nullable=False),
        sa.Column("user_id", UUID(as_uuid=True), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
        sa.Column("team_id", UUID(as_uuid=True), sa.ForeignKey("teams.id", ondelete="SET NULL"), nullable=True),
        sa.Column("session_id", UUID(as_uuid=True), sa.ForeignKey("sessions.id", ondelete="SET NULL"), nullable=True),
        sa.Column("parameters_used", JSONB, nullable=False, server_default=sa.text("'{}'::jsonb")),
        sa.Column("generated_script", sa.Text, nullable=False),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
    )
    op.create_index("ix_script_generations_template_id", "script_generations", ["template_id"])
    op.create_index("ix_script_generations_user_id", "script_generations", ["user_id"])
    op.create_index("ix_script_generations_session_id", "script_generations", ["session_id"])

    # ── Seed: Active Directory category ──────────────────────────────────
    now = datetime.now(timezone.utc)
    cat_id = uuid.UUID("00000000-0000-0000-0000-000000000001")

    conn = op.get_bind()
    conn.execute(
        sa.text("""
            INSERT INTO script_categories (id, name, slug, description, icon, sort_order, is_active, created_at, updated_at)
            VALUES (:id, :name, :slug, :description, :icon, :sort_order, true, :now, :now)
        """),
        {
            "id": cat_id,
            "name": "Active Directory",
            "slug": "active-directory",
            "description": "User account and group management scripts for Active Directory environments",
            "icon": "shield-check",
            "sort_order": 1,
            "now": now,
        }
    )

    templates = _get_seed_templates(cat_id, now)
    for tmpl in templates:
        conn.execute(
            sa.text("""
                INSERT INTO script_templates (
                    id, category_id, name, slug, description, use_case,
                    script_body, parameters_schema, default_values, validation_rules,
                    tags, complexity, estimated_runtime, requires_elevation,
                    requires_modules, version, is_verified, is_active, usage_count,
                    created_at, updated_at
                ) VALUES (
                    :id, :category_id, :name, :slug, :description, :use_case,
                    :script_body, CAST(:parameters_schema AS jsonb), CAST(:default_values AS jsonb), CAST(:validation_rules AS jsonb),
                    CAST(:tags AS jsonb), :complexity, :estimated_runtime, :requires_elevation,
                    CAST(:requires_modules AS jsonb), 1, true, true, 0,
                    :now, :now
                )
            """),
            tmpl,
        )


def downgrade() -> None:
    op.drop_table("script_generations")
    op.drop_table("script_templates")
    op.drop_table("script_categories")
    op.execute("DROP TYPE IF EXISTS script_complexity")


def _get_seed_templates(cat_id: uuid.UUID, now: datetime) -> list[dict]:
    """Return seed data for the six AD User Management templates."""

    def tmpl(
        id_suffix: int,
        name: str,
        slug: str,
        description: str,
        use_case: str,
        script_body: str,
        parameters_schema: dict,
        complexity: str,
        estimated_runtime: str,
        requires_elevation: bool,
        tags: list[str],
    ) -> dict:
        return {
            "id": uuid.UUID(f"00000000-0000-0000-0001-{id_suffix:012d}"),
            "category_id": cat_id,
            "name": name,
            "slug": slug,
            "description": description,
            "use_case": use_case,
            "script_body": script_body,
            "parameters_schema": json.dumps(parameters_schema),
            "default_values": json.dumps({}),
            "validation_rules": json.dumps({}),
            "tags": json.dumps(tags),
            "complexity": complexity,
            "estimated_runtime": estimated_runtime,
            "requires_elevation": requires_elevation,
            "requires_modules": json.dumps([]),
            "now": now,
        }

    return [

        # ── 1: Create AD User ─────────────────────────────────────────────
        tmpl(
            id_suffix=1,
            name="Create AD User Account",
            slug="create-ad-user",
            description="Creates a new Active Directory user account with full property configuration.",
            use_case="Use when onboarding a new employee or creating a service account in Active Directory.",
            complexity="intermediate",
            estimated_runtime="< 5 seconds",
            requires_elevation=True,
            tags=["active-directory", "user-management", "onboarding"],
            parameters_schema={
                "parameters": [
                    {"key": "first_name", "label": "First Name", "type": "text", "required": True, "group": "User Identity", "order": 1, "validation": {"pattern": "^[a-zA-Z\\-']+$", "maxLength": 64}},
                    {"key": "last_name", "label": "Last Name", "type": "text", "required": True, "group": "User Identity", "order": 2, "validation": {"pattern": "^[a-zA-Z\\-']+$", "maxLength": 64}},
                    {"key": "sam_account_name", "label": "SAM Account Name", "type": "text", "required": True, "group": "User Identity", "order": 3, "placeholder": "jsmith", "help_text": "The logon name (typically firstname.lastname or first initial + last name). Max 20 characters."},
                    {"key": "upn_suffix", "label": "UPN Suffix", "type": "text", "required": True, "group": "User Identity", "order": 4, "placeholder": "contoso.com"},
                    {"key": "ou_path", "label": "Organizational Unit", "type": "text", "required": True, "group": "AD Configuration", "order": 5, "placeholder": "OU=Users,DC=contoso,DC=com", "validation": {"pattern": "^(OU|CN)=.+"}},
                    {"key": "password", "label": "Initial Password", "type": "password", "required": True, "group": "Security", "order": 6, "sensitive": True},
                    {"key": "job_title", "label": "Job Title", "type": "text", "required": False, "group": "Profile", "order": 7},
                    {"key": "department", "label": "Department", "type": "text", "required": False, "group": "Profile", "order": 8},
                    {"key": "groups", "label": "Security Groups", "type": "multi_text", "required": False, "group": "Group Membership", "order": 9, "placeholder": "Domain Users"},
                    {"key": "force_password_change", "label": "Force Password Change at Logon", "type": "boolean", "required": False, "group": "Security", "order": 10, "default": True},
                    {"key": "account_enabled", "label": "Enable Account", "type": "boolean", "required": False, "group": "Security", "order": 11, "default": True},
                ]
            },
            script_body=r"""# ============================================================
# Create AD User Account
# Generated by ResolutionFlow Script Generator
# Template Version: 1
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$FirstName          = '{{ first_name }}'
$LastName           = '{{ last_name }}'
$SamAccountName     = '{{ sam_account_name }}'
$UPNSuffix          = '{{ upn_suffix }}'
$OUPath             = '{{ ou_path }}'
$Password           = {{ password | as_secure_string }}
$ForcePasswordChange = {{ force_password_change | as_bool }}
$AccountEnabled     = {{ account_enabled | as_bool }}
{% if job_title %}
$JobTitle           = '{{ job_title }}'
{% endif %}
{% if department %}
$Department         = '{{ department }}'
{% endif %}
{% if groups %}
$Groups             = @({{ groups | as_array }})
{% endif %}

$DisplayName        = "$FirstName $LastName"
$UPN                = "$SamAccountName@$UPNSuffix"

try {
    Import-Module ActiveDirectory -ErrorAction Stop
    Write-Host "[CHECK] ActiveDirectory module loaded" -ForegroundColor Green
} catch {
    Write-Host "[ERROR] ActiveDirectory module not available: $_" -ForegroundColor Red
    exit 1
}

try {
    $userParams = @{
        Name              = $DisplayName
        GivenName         = $FirstName
        Surname           = $LastName
        SamAccountName    = $SamAccountName
        UserPrincipalName = $UPN
        Path              = $OUPath
        AccountPassword   = $Password
        Enabled           = $AccountEnabled
        ChangePasswordAtLogon = $ForcePasswordChange
    }
{% if job_title %}
    $userParams["Title"] = $JobTitle
{% endif %}
{% if department %}
    $userParams["Department"] = $Department
{% endif %}

    New-ADUser @userParams -ErrorAction Stop
    Write-Host "[OK] User account created: $SamAccountName ($DisplayName)" -ForegroundColor Green
} catch {
    Write-Host "[ERROR] Failed to create user: $_" -ForegroundColor Red
    exit 1
}

{% if groups %}
foreach ($group in $Groups) {
    try {
        Add-ADGroupMember -Identity $group -Members $SamAccountName -ErrorAction Stop
        Write-Host "[OK] Added to group: $group" -ForegroundColor Green
    } catch {
        Write-Host "[WARN] Could not add to group '$group': $_" -ForegroundColor Yellow
    }
}
{% endif %}

Write-Host ""
Write-Host "[DONE] User $SamAccountName created successfully." -ForegroundColor Cyan
Write-Host "       UPN: $UPN" -ForegroundColor Cyan
""",
        ),

        # ── 2: Disable AD User ────────────────────────────────────────────
        tmpl(
            id_suffix=2,
            name="Disable AD User Account",
            slug="disable-ad-user",
            description="Disables an Active Directory user account with optional group removal and OU relocation.",
            use_case="Use when offboarding an employee or temporarily suspending access.",
            complexity="beginner",
            estimated_runtime="< 5 seconds",
            requires_elevation=True,
            tags=["active-directory", "user-management", "offboarding"],
            parameters_schema={
                "parameters": [
                    {"key": "sam_account_name", "label": "SAM Account Name", "type": "text", "required": True, "group": "Target Account", "order": 1, "placeholder": "jsmith"},
                    {"key": "disable_reason", "label": "Reason", "type": "text", "required": False, "group": "Audit", "order": 2, "placeholder": "Employee offboarding"},
                    {"key": "remove_groups", "label": "Remove from All Groups", "type": "boolean", "required": False, "group": "Options", "order": 3, "default": False},
                    {"key": "move_to_disabled_ou", "label": "Move to Disabled OU", "type": "boolean", "required": False, "group": "Options", "order": 4, "default": False},
                    {"key": "disabled_ou_path", "label": "Disabled OU Path", "type": "text", "required": False, "group": "Options", "order": 5, "placeholder": "OU=Disabled,DC=contoso,DC=com"},
                ]
            },
            script_body=r"""# ============================================================
# Disable AD User Account
# Generated by ResolutionFlow Script Generator
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$SamAccountName  = '{{ sam_account_name }}'
{% if disable_reason %}
$DisableReason   = '{{ disable_reason }}'
{% endif %}
$RemoveGroups    = {{ remove_groups | as_bool }}
$MoveToDisabled  = {{ move_to_disabled_ou | as_bool }}
{% if disabled_ou_path %}
$DisabledOUPath  = '{{ disabled_ou_path }}'
{% endif %}

try {
    Import-Module ActiveDirectory -ErrorAction Stop
} catch {
    Write-Host "[ERROR] ActiveDirectory module not available: $_" -ForegroundColor Red; exit 1
}

try {
    $user = Get-ADUser -Identity $SamAccountName -Properties MemberOf -ErrorAction Stop
    Write-Host "[CHECK] Found user: $($user.DistinguishedName)" -ForegroundColor Green
} catch {
    Write-Host "[ERROR] User not found: $SamAccountName" -ForegroundColor Red; exit 1
}

try {
    Disable-ADAccount -Identity $SamAccountName -ErrorAction Stop
    Write-Host "[OK] Account disabled: $SamAccountName" -ForegroundColor Green
{% if disable_reason %}
    Set-ADUser -Identity $SamAccountName -Description $DisableReason
    Write-Host "[OK] Disable reason recorded in Description field" -ForegroundColor Green
{% endif %}
} catch {
    Write-Host "[ERROR] Failed to disable account: $_" -ForegroundColor Red; exit 1
}

{% if remove_groups %}
if ($RemoveGroups) {
    $groups = $user.MemberOf
    foreach ($group in $groups) {
        try {
            Remove-ADGroupMember -Identity $group -Members $SamAccountName -Confirm:$false -ErrorAction Stop
            Write-Host "[OK] Removed from group: $group" -ForegroundColor Green
        } catch {
            Write-Host "[WARN] Could not remove from group: $group" -ForegroundColor Yellow
        }
    }
}
{% endif %}

{% if move_to_disabled_ou %}
if ($MoveToDisabled) {
    try {
        Move-ADObject -Identity $user.DistinguishedName -TargetPath $DisabledOUPath -ErrorAction Stop
        Write-Host "[OK] Moved to disabled OU: $DisabledOUPath" -ForegroundColor Green
    } catch {
        Write-Host "[WARN] Could not move to disabled OU: $_" -ForegroundColor Yellow
    }
}
{% endif %}

Write-Host ""
Write-Host "[DONE] Account $SamAccountName has been disabled." -ForegroundColor Cyan
""",
        ),

        # ── 3: Reset AD Password ──────────────────────────────────────────
        tmpl(
            id_suffix=3,
            name="Reset AD Password",
            slug="reset-ad-password",
            description="Resets an Active Directory user password with optional account unlock.",
            use_case="Use when a user has forgotten their password or their account is locked out.",
            complexity="beginner",
            estimated_runtime="< 5 seconds",
            requires_elevation=True,
            tags=["active-directory", "password", "account-management"],
            parameters_schema={
                "parameters": [
                    {"key": "sam_account_name", "label": "SAM Account Name", "type": "text", "required": True, "group": "Target Account", "order": 1},
                    {"key": "new_password", "label": "New Password", "type": "password", "required": True, "group": "Security", "order": 2, "sensitive": True},
                    {"key": "force_change_at_logon", "label": "Force Change at Next Logon", "type": "boolean", "required": False, "group": "Security", "order": 3, "default": True},
                    {"key": "unlock_account", "label": "Unlock Account if Locked", "type": "boolean", "required": False, "group": "Options", "order": 4, "default": True},
                ]
            },
            script_body=r"""# ============================================================
# Reset AD Password
# Generated by ResolutionFlow Script Generator
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$SamAccountName    = '{{ sam_account_name }}'
$NewPassword       = {{ new_password | as_secure_string }}
$ForceChange       = {{ force_change_at_logon | as_bool }}
$UnlockAccount     = {{ unlock_account | as_bool }}

try { Import-Module ActiveDirectory -ErrorAction Stop } catch { Write-Host "[ERROR] $_ " -ForegroundColor Red; exit 1 }

try {
    Set-ADAccountPassword -Identity $SamAccountName -NewPassword $NewPassword -Reset -ErrorAction Stop
    Write-Host "[OK] Password reset for: $SamAccountName" -ForegroundColor Green
} catch {
    Write-Host "[ERROR] Failed to reset password: $_" -ForegroundColor Red; exit 1
}

if ($ForceChange) {
    Set-ADUser -Identity $SamAccountName -ChangePasswordAtLogon $true
    Write-Host "[OK] User must change password at next logon" -ForegroundColor Green
}

if ($UnlockAccount) {
    try {
        Unlock-ADAccount -Identity $SamAccountName -ErrorAction Stop
        Write-Host "[OK] Account unlocked" -ForegroundColor Green
    } catch {
        Write-Host "[WARN] Could not unlock account (may not have been locked): $_" -ForegroundColor Yellow
    }
}

Write-Host ""
Write-Host "[DONE] Password reset complete for $SamAccountName." -ForegroundColor Cyan
""",
        ),

        # ── 4: Unlock AD Account ──────────────────────────────────────────
        tmpl(
            id_suffix=4,
            name="Unlock AD Account",
            slug="unlock-ad-account",
            description="Unlocks a locked-out Active Directory user account and optionally shows lockout information.",
            use_case="Use when a user is locked out after too many failed login attempts.",
            complexity="beginner",
            estimated_runtime="< 5 seconds",
            requires_elevation=True,
            tags=["active-directory", "account-management", "lockout"],
            parameters_schema={
                "parameters": [
                    {"key": "sam_account_name", "label": "SAM Account Name", "type": "text", "required": True, "group": "Target Account", "order": 1},
                    {"key": "show_lockout_info", "label": "Show Lockout Source Info", "type": "boolean", "required": False, "group": "Options", "order": 2, "default": False, "help_text": "Queries domain controllers for lockout source (may be slow)"},
                ]
            },
            script_body=r"""# ============================================================
# Unlock AD Account
# Generated by ResolutionFlow Script Generator
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$SamAccountName  = '{{ sam_account_name }}'
$ShowLockoutInfo = {{ show_lockout_info | as_bool }}

try { Import-Module ActiveDirectory -ErrorAction Stop } catch { Write-Host "[ERROR] $_ " -ForegroundColor Red; exit 1 }

try {
    $user = Get-ADUser -Identity $SamAccountName -Properties LockedOut, BadLogonCount, LastBadPasswordAttempt -ErrorAction Stop
    Write-Host "[CHECK] User found: $($user.DistinguishedName)" -ForegroundColor Green
    Write-Host "        Locked Out: $($user.LockedOut)" -ForegroundColor Cyan
    Write-Host "        Bad Logon Count: $($user.BadLogonCount)" -ForegroundColor Cyan
    Write-Host "        Last Bad Password Attempt: $($user.LastBadPasswordAttempt)" -ForegroundColor Cyan
} catch {
    Write-Host "[ERROR] User not found: $SamAccountName" -ForegroundColor Red; exit 1
}

if (-not $user.LockedOut) {
    Write-Host "[INFO] Account is not currently locked." -ForegroundColor Yellow
} else {
    try {
        Unlock-ADAccount -Identity $SamAccountName -ErrorAction Stop
        Write-Host "[OK] Account unlocked: $SamAccountName" -ForegroundColor Green
    } catch {
        Write-Host "[ERROR] Failed to unlock account: $_" -ForegroundColor Red; exit 1
    }
}

{% if show_lockout_info %}
if ($ShowLockoutInfo) {
    Write-Host ""
    Write-Host "[INFO] Querying domain controllers for lockout source..." -ForegroundColor Cyan
    try {
        $DCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
        foreach ($DC in $DCs) {
            $events = Get-WinEvent -ComputerName $DC -FilterHashtable @{
                LogName   = "Security"
                Id        = 4740
            } -MaxEvents 10 -ErrorAction SilentlyContinue |
            Where-Object { $_.Properties[0].Value -eq $SamAccountName }
            foreach ($e in $events) {
                Write-Host "  DC: $DC | Source: $($e.Properties[1].Value) | Time: $($e.TimeCreated)" -ForegroundColor Yellow
            }
        }
    } catch {
        Write-Host "[WARN] Could not query lockout source: $_" -ForegroundColor Yellow
    }
}
{% endif %}

Write-Host ""
Write-Host "[DONE] Unlock operation complete for $SamAccountName." -ForegroundColor Cyan
""",
        ),

        # ── 5: Delete AD User ─────────────────────────────────────────────
        tmpl(
            id_suffix=5,
            name="Delete AD User Account",
            slug="delete-ad-user",
            description="Permanently deletes an Active Directory user account with optional CSV backup of user properties.",
            use_case="Use when permanently removing an account that is no longer needed. Prefer Disable for departing employees.",
            complexity="advanced",
            estimated_runtime="< 10 seconds",
            requires_elevation=True,
            tags=["active-directory", "user-management", "destructive"],
            parameters_schema={
                "parameters": [
                    {"key": "sam_account_name", "label": "SAM Account Name", "type": "text", "required": True, "group": "Target Account", "order": 1},
                    {"key": "confirm_deletion", "label": "I confirm this account should be permanently deleted", "type": "boolean", "required": True, "group": "Confirmation", "order": 2, "default": False},
                    {"key": "backup_to_csv", "label": "Back Up User Properties to CSV First", "type": "boolean", "required": False, "group": "Options", "order": 3, "default": True},
                    {"key": "backup_path", "label": "CSV Backup Path", "type": "text", "required": False, "group": "Options", "order": 4, "placeholder": "C:\\Backups\\ad-user-backup.csv"},
                ]
            },
            script_body=r"""# ============================================================
# Delete AD User Account
# Generated by ResolutionFlow Script Generator
# DESTRUCTIVE OPERATION
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$SamAccountName  = '{{ sam_account_name }}'
$ConfirmDeletion = {{ confirm_deletion | as_bool }}
$BackupToCSV     = {{ backup_to_csv | as_bool }}
{% if backup_path %}
$BackupPath      = '{{ backup_path }}'
{% else %}
$BackupPath      = "C:\Temp\ad-user-backup-$SamAccountName-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv"
{% endif %}

try { Import-Module ActiveDirectory -ErrorAction Stop } catch { Write-Host "[ERROR] $_ " -ForegroundColor Red; exit 1 }

if (-not $ConfirmDeletion) {
    Write-Host "[ABORT] Deletion not confirmed. Set confirm_deletion to true to proceed." -ForegroundColor Red
    exit 1
}

try {
    $user = Get-ADUser -Identity $SamAccountName -Properties * -ErrorAction Stop
    Write-Host "[CHECK] Found user: $($user.DistinguishedName)" -ForegroundColor Yellow
    Write-Host "[WARN]  About to permanently delete this account." -ForegroundColor Yellow
} catch {
    Write-Host "[ERROR] User not found: $SamAccountName" -ForegroundColor Red; exit 1
}

if ($BackupToCSV) {
    try {
        $user | Select-Object Name, SamAccountName, UserPrincipalName, DistinguishedName, EmailAddress, Title, Department, Enabled, Created, Modified |
            Export-Csv -Path $BackupPath -NoTypeInformation -ErrorAction Stop
        Write-Host "[OK] User properties backed up to: $BackupPath" -ForegroundColor Green
    } catch {
        Write-Host "[WARN] Could not write backup: $_" -ForegroundColor Yellow
    }
}

try {
    Remove-ADUser -Identity $SamAccountName -Confirm:$false -ErrorAction Stop
    Write-Host "[OK] User account permanently deleted: $SamAccountName" -ForegroundColor Green
} catch {
    Write-Host "[ERROR] Failed to delete user: $_" -ForegroundColor Red; exit 1
}

Write-Host ""
Write-Host "[DONE] Account $SamAccountName has been permanently deleted." -ForegroundColor Cyan
""",
        ),

        # ── 6: Bulk User Import ───────────────────────────────────────────
        tmpl(
            id_suffix=6,
            name="Bulk User Import from CSV",
            slug="bulk-user-import",
            description="Imports multiple Active Directory user accounts from a CSV file with dry-run support and detailed logging.",
            use_case="Use when onboarding multiple employees at once from an HR system export.",
            complexity="advanced",
            estimated_runtime="1-2 minutes",
            requires_elevation=True,
            tags=["active-directory", "bulk", "onboarding", "csv"],
            parameters_schema={
                "parameters": [
                    {"key": "csv_path", "label": "CSV File Path", "type": "text", "required": True, "group": "Source", "order": 1, "placeholder": "C:\\Imports\\new-users.csv", "help_text": "CSV must have columns: FirstName, LastName, SamAccountName, UPN, Department, JobTitle"},
                    {"key": "ou_path", "label": "Target Organizational Unit", "type": "text", "required": True, "group": "AD Configuration", "order": 2, "placeholder": "OU=Users,DC=contoso,DC=com"},
                    {"key": "default_password", "label": "Default Password", "type": "password", "required": True, "group": "Security", "order": 3, "sensitive": True},
                    {"key": "groups", "label": "Add All Users to Groups", "type": "multi_text", "required": False, "group": "Group Membership", "order": 4},
                    {"key": "force_password_change", "label": "Force Password Change at Logon", "type": "boolean", "required": False, "group": "Security", "order": 5, "default": True},
                    {"key": "log_path", "label": "Log File Path", "type": "text", "required": False, "group": "Options", "order": 6, "placeholder": "C:\\Logs\\bulk-import.log"},
                    {"key": "dry_run", "label": "Dry Run (Preview Only - No Changes Made)", "type": "boolean", "required": False, "group": "Options", "order": 7, "default": False},
                ]
            },
            script_body=r"""# ============================================================
# Bulk User Import from CSV
# Generated by ResolutionFlow Script Generator
# ============================================================
# CSV Format: FirstName, LastName, SamAccountName, UPN, Department, JobTitle
# ============================================================

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

$CSVPath         = '{{ csv_path }}'
$OUPath          = '{{ ou_path }}'
$DefaultPassword = {{ default_password | as_secure_string }}
$ForceChange     = {{ force_password_change | as_bool }}
$DryRun          = {{ dry_run | as_bool }}
{% if log_path %}
$LogPath         = '{{ log_path }}'
{% else %}
$LogPath         = "C:\Temp\bulk-import-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
{% endif %}
{% if groups %}
$DefaultGroups   = @({{ groups | as_array }})
{% endif %}

function Write-Log {
    param($Message, $Level = "INFO")
    $line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] $Message"
    Add-Content -Path $LogPath -Value $line -ErrorAction SilentlyContinue
    $color = switch ($Level) { "ERROR" { "Red" } "WARN" { "Yellow" } "OK" { "Green" } default { "White" } }
    Write-Host $line -ForegroundColor $color
}

try { Import-Module ActiveDirectory -ErrorAction Stop } catch { Write-Log "ActiveDirectory module not available: $_" "ERROR"; exit 1 }

if (-not (Test-Path $CSVPath)) { Write-Log "CSV file not found: $CSVPath" "ERROR"; exit 1 }

$users = Import-Csv -Path $CSVPath
Write-Log "Loaded $($users.Count) users from CSV"
if ($DryRun) { Write-Log "DRY RUN MODE - no changes will be made" "WARN" }

$successCount = 0
$errorCount = 0

foreach ($row in $users) {
    $sam = $row.SamAccountName
    try {
        $existing = Get-ADUser -Filter "SamAccountName -eq '$sam'" -ErrorAction SilentlyContinue
        if ($existing) { Write-Log "SKIP: $sam already exists" "WARN"; continue }

        if (-not $DryRun) {
            New-ADUser `
                -Name "$($row.FirstName) $($row.LastName)" `
                -GivenName $row.FirstName `
                -Surname $row.LastName `
                -SamAccountName $sam `
                -UserPrincipalName $row.UPN `
                -Path $OUPath `
                -AccountPassword $DefaultPassword `
                -Enabled $true `
                -ChangePasswordAtLogon $ForceChange `
                -Title $row.JobTitle `
                -Department $row.Department `
                -ErrorAction Stop

{% if groups %}
            foreach ($group in $DefaultGroups) {
                try { Add-ADGroupMember -Identity $group -Members $sam -ErrorAction Stop }
                catch { Write-Log "WARN: $sam - could not add to group '$group'" "WARN" }
            }
{% endif %}
        }
        Write-Log "$(if ($DryRun) { 'PREVIEW' } else { 'CREATED' }): $sam ($($row.FirstName) $($row.LastName))" "OK"
        $successCount++
    } catch {
        Write-Log "FAILED: $sam - $_" "ERROR"
        $errorCount++
    }
}

Write-Log ""
Write-Log "[DONE] Import complete. Success: $successCount | Errors: $errorCount | Log: $LogPath" "INFO"
""",
        ),

    ]
