use super::SchemaKind;

pub fn get_schema(kind: SchemaKind) -> &'static str {
    match kind {
        SchemaKind::Module => MODULE_SCHEMA,
        SchemaKind::Profile => PROFILE_SCHEMA,
        SchemaKind::Config => CONFIG_SCHEMA,
    }
}

const MODULE_SCHEMA: &str = r#"# cfgd Module schema — cfgd.io/v1alpha1
# A Module is a self-contained, portable configuration package.
# It bundles packages, config files, env vars, aliases, and scripts for one tool.

apiVersion: cfgd.io/v1alpha1  # required, always this value
kind: Module                   # required, always "Module"

metadata:
  name: example                # required, string — unique module name (used in profile modules list)
  description: Example module  # optional, string — human-readable description

spec:
  # List of module names this module depends on.
  # Dependencies are installed before this module. Circular deps are rejected.
  # optional, default: []
  depends:
    - node
    - python

  # Cross-platform package declarations.
  # Each entry describes one logical package with platform-aware resolution.
  # optional, default: []
  packages:
    - name: neovim             # required, string — canonical package name
      minVersion: "0.9"         # optional, string — minimum semver version (e.g. "0.9", "18.0.0")
      # optional, list of strings — ordered list of package managers to try.
      # Values: brew, apt, dnf, yum, pacman, apk, zypper, pkg, snap, flatpak, nix, go, cargo, npm, pipx, script.
      # If "script" is in the list, the script field must be present.
      # If omitted, uses the platform's native manager.
      prefer:
        - brew
        - snap
        - apt
      # optional, map of string->string — per-manager package name overrides.
      # Use when the package has a different name in a specific manager's repository.
      aliases:
        apt: neovim-nightly
        snap: nvim
      # optional, string — inline shell script or path (relative to module dir).
      # Used when prefer includes "script". Runs with /bin/sh -e.
      script: curl -fsSL https://example.com/install.sh | sh
      # optional, list of strings — package managers to never use for this package.
      deny:
        - snap
      # optional, list of strings — platform filter.
      # Values: OS (linux, macos), distro (ubuntu, fedora, arch, debian, alpine, opensuse, freebsd),
      # or arch (x86_64, aarch64). Package is skipped on non-matching platforms.
      platforms:
        - linux
        - macos

  # File entries to deploy. Source can be local (relative to module dir) or a git URL.
  # optional, default: []
  files:
    - source: config/           # required, string — local path relative to module dir
      target: ~/.config/nvim/   # required, string — absolute target path (~ is expanded)
      # optional, string — deployment strategy override: Symlink, Copy, Template, Hardlink.
      # If omitted, uses the global fileStrategy from Config (default: Symlink).
      strategy: Symlink
      # optional, bool, default: false — when true, file is local-only (added to .gitignore,
      # silently skipped on machines where it doesn't exist).
      private: false

    # Git URL source — clone/fetch from a remote repo
    - source: https://github.com/user/nvim-config.git@v2.1.0  # @tag or ?ref=branch, //subdir
      target: ~/.config/nvim/

  # Environment variables set by this module.
  # Merged with profile env vars; module wins on name conflict.
  # optional, default: []
  env:
    - name: EDITOR              # required, string — variable name
      value: nvim               # required, string — variable value

  # Shell aliases set by this module.
  # Merged with profile aliases; module wins on name conflict.
  # For bash/zsh: alias name="command". For fish: abbr -a name command.
  # optional, default: []
  aliases:
    - name: vim                 # required, string — alias name
      command: nvim             # required, string — alias command

  # System configurator settings contributed by this module.
  # Deep-merged into the profile system map; module values override profile values at leaf level.
  # Keys must match a registered system configurator (e.g. git, sshKeys, gpgKeys).
  # optional, default: {}
  system:
    git:
      user.name: Jane Doe
      user.email: jane@example.com
    sshKeys:
      - path: ~/.ssh/id_ed25519.pub
        comment: jane@example.com

  # Lifecycle scripts. Run after all packages and files are deployed.
  # optional
  scripts:
    # List of shell commands to run after apply. Each runs with /bin/sh -e
    # in the module directory. If one fails, subsequent scripts are skipped.
    # optional, default: []
    postApply:
      - nvim --headless "+Lazy! sync" +qa
      - nvim --headless -c "MasonInstallAll" -c "qa"
"#;

const PROFILE_SCHEMA: &str = r#"# cfgd Profile schema — cfgd.io/v1alpha1
# A Profile declares the desired state of a machine: packages, files, env, system settings.
# Profiles can inherit from other profiles to share common configuration.

apiVersion: cfgd.io/v1alpha1  # required, always this value
kind: Profile                  # required, always "Profile"

metadata:
  name: work                   # required, string — profile name (filename without .yaml)

spec:
  # Parent profiles to inherit from, processed left-to-right.
  # The active profile is applied last and wins on conflicts.
  # Merge rules: env/aliases=override by name, packages=union, files=overlay by target,
  # system=deep merge, secrets=append (dedup by target), scripts=append, modules=union.
  # optional, default: []
  inherits:
    - base
    - macos

  # Module names to include. Modules provide portable, cross-platform tool configs.
  # Use "<registry>/<module>" for registry modules (e.g. "community/tmux").
  # optional, default: []
  modules:
    - nvim
    - tmux
    - community/tmux

  # Environment variables — name/value pairs exported to shell and available in Tera templates.
  # Later profile overrides earlier for the same name. Module env wins over profile env.
  # optional, default: []
  env:
    - name: EDITOR              # required, string — variable name
      value: nvim               # required, string — variable value
    - name: GIT_AUTHOR_NAME
      value: Jane Doe

  # Shell aliases — name/command pairs written to ~/.cfgd.env (bash/zsh) or fish conf.d.
  # Later profile overrides earlier for the same name. Module aliases win over profile aliases.
  # optional, default: []
  aliases:
    - name: vim                 # required, string — alias name
      command: nvim             # required, string — alias command
    - name: k
      command: kubectl

  # Per-manager package declarations.
  # optional
  packages:
    # Homebrew (macOS, Linux)
    brew:
      file: Brewfile            # optional, string — path to Brewfile
      taps:                     # optional, list of strings — custom taps to add
        - homebrew/cask-fonts
      formulae:                 # optional, list of strings — formulae to install
        - git
        - ripgrep
        - jq
      casks:                    # optional, list of strings — casks to install
        - 1password
        - wezterm

    # APT (Debian, Ubuntu)
    apt:
      file: packages.txt        # optional, string — path to package list file
      packages:                  # optional, list of strings
        - build-essential
        - curl

    # Cargo (Rust) — accepts list form or object form
    # List form: cargo: [bat, eza]
    # Object form shown below:
    cargo:
      file: Cargo.toml          # optional, string — path to Cargo.toml with [dependencies]
      packages:                  # optional, list of strings
        - bat
        - eza

    # npm (Node.js)
    npm:
      file: package.json         # optional, string — path to package.json
      global:                    # optional, list of strings — globally installed packages
        - typescript
        - prettier

    # pipx (Python)
    # list of strings
    pipx:
      - httpie
      - ruff

    # DNF (Fedora, RHEL 8+)
    # list of strings
    dnf:
      - gcc
      - make

    # APK (Alpine)
    # list of strings
    apk:
      - build-base

    # Pacman (Arch, Manjaro)
    # list of strings
    pacman:
      - base-devel

    # Zypper (openSUSE)
    # list of strings
    zypper:
      - gcc

    # Yum (RHEL 7, CentOS 7)
    # list of strings
    yum:
      - gcc

    # pkg (FreeBSD)
    # list of strings
    pkg:
      - curl

    # Snap (Ubuntu, other Linux)
    snap:
      packages:                  # optional, list of strings — strict confinement snaps
        - firefox
      classic:                   # optional, list of strings — classic confinement snaps
        - code

    # Flatpak
    flatpak:
      packages:                  # optional, list of strings — Flatpak app IDs
        - org.mozilla.firefox
      remote: flathub            # optional, string — remote name (default: flathub)

    # Nix
    # list of strings — Nix package names
    nix:
      - direnv

    # Go
    # list of strings — Go package paths (go install)
    go:
      - golang.org/x/tools/gopls@latest

    # winget (Windows Package Manager)
    # list of strings — winget package IDs
    winget:
      - Microsoft.VisualStudioCode
      - Git.Git

    # Chocolatey (Windows)
    # list of strings — Chocolatey package names
    chocolatey:
      - nodejs
      - 7zip

    # Scoop (Windows)
    # list of strings — Scoop package names
    scoop:
      - ripgrep
      - fd

    # Custom package managers
    # list of objects, each defining how to interact with a custom manager
    custom:
      - name: my-manager        # required, string — manager name
        check: which my-mgr     # required, string — command to check if manager exists
        listInstalled: my-mgr list   # required, string — command to list installed packages
        install: my-mgr install      # required, string — install command template
        uninstall: my-mgr remove     # required, string — uninstall command template
        update: my-mgr upgrade       # optional, string — update command template
        packages:                     # optional, list of strings
          - custom-pkg

  # File management — source files deployed to target locations.
  # optional
  files:
    # List of managed file entries.
    # optional, default: []
    managed:
      - source: shell/.zshrc       # required, string — path relative to config repo files/ dir
        target: ~/.zshrc            # required, string — absolute target path (~ expanded)
        strategy: Symlink           # optional: Symlink (default), Copy, Template, Hardlink
        private: false              # optional, bool, default: false — local-only file
      - source: git/.gitconfig.tera # .tera extension auto-selects template strategy
        target: ~/.gitconfig

    # Permission overrides — map of target path to octal permission string.
    # optional, default: {}
    permissions:
      "~/.ssh/config": "600"
      "~/.ssh": "700"

  # System configurator settings — a map of configurator name to its config value.
  # Available configurators depend on the platform. Unknown keys are silently skipped.
  # optional, default: {}
  system:
    # Set default login shell (all platforms)
    shell: /bin/zsh               # string — path to shell binary

    # macOS defaults domains (macOS only)
    macosDefaults:
      NSGlobalDomain:
        AppleShowAllExtensions: true
      com.apple.dock:
        autohide: true
        tilesize: 48

    # LaunchAgent plist management (macOS only)
    launchAgents:
      - name: com.example.myservice    # required, string — service label
        program: /usr/local/bin/myservice  # required, string — executable path
        args:                              # optional, list of strings
          - "--config"
          - "/etc/myservice.conf"
        runAtLoad: true                    # optional, bool

    # systemd user unit management (Linux only)
    systemdUnits:
      - name: myservice.service    # required, string — unit name
        unitFile: systemd/myservice.service  # required, string — path to unit file
        enabled: true              # optional, bool

    # GNOME/GTK desktop settings via gsettings (Linux only)
    gsettings:
      org.gnome.desktop.interface:
        color-scheme: prefer-dark       # string — gsettings schema.key
        font-name: "Cantarell 11"
      org.gnome.desktop.wm.preferences:
        button-layout: "close,minimize,maximize:"

    # KDE Plasma settings via kwriteconfig (Linux only)
    kdeConfig:
      kdeglobals:                       # config file name
        General:                        # group within file
          ColorScheme: BreezeDark       # key: value
        KDE:
          LookAndFeelPackage: org.kde.breezedark.desktop

    # XFCE desktop settings via xfconf-query (Linux only)
    xfconf:
      xfwm4:
        /general/theme: Default         # channel.property: value
        /general/title_font: "Sans Bold 9"

    # Shell environment file management (all platforms)
    environment:
      GOPATH: ~/go
      EDITOR: nvim

    # Kernel sysctl parameters (Linux, typically node/k8s context)
    sysctl:
      net.ipv4.ip_forward: 1
      vm.max_map_count: 262144

    # Kernel modules to load (Linux, typically node/k8s context)
    kernelModules:
      - br_netfilter
      - overlay

    # containerd configuration (Linux, node/k8s context)
    containerd:
      configPath: /etc/containerd/config.toml

    # kubelet configuration (Linux, node/k8s context)
    kubelet:
      configPath: /var/lib/kubelet/config.yaml

    # AppArmor profiles (Linux, node/k8s context)
    apparmor:
      profiles:
        - /etc/apparmor.d/my-profile

    # Seccomp profiles (Linux, node/k8s context)
    seccomp:
      profilesDir: /var/lib/kubelet/seccomp

    # Certificate management (Linux, node/k8s context)
    certificates:
      caCerts:
        - /usr/local/share/ca-certificates/my-ca.crt

    # Windows registry settings (Windows only)
    # Keys are registry paths (e.g. HKCU\Software\...), values are name-value maps
    windowsRegistry:
      HKCU\Software\Example:
        MyValue: hello
        MyDword: 42

    # Windows Service management (Windows only)
    windowsServices:
      - name: MyService              # required, string — service name
        displayName: My Service      # optional, string — display name
        binaryPath: C:\svc\svc.exe  # required (for create), string — executable path
        startType: auto              # optional: auto, manual, disabled (default: auto)
        state: running               # optional: running, stopped (default: running)

  # Secret file declarations — SOPS-encrypted files or external secret provider references.
  # optional, default: []
  secrets:
    - source: secrets/api-keys.yaml        # required, string — SOPS file path or provider URI
      target: ~/.config/api-keys.yaml      # required, string — target path for decrypted output
      template: "token: ${secret:value}"   # optional, string — template for formatting output
      backend: sops                        # optional, string — override backend (sops, 1password, bitwarden, vault)
    - source: 1password://Work/GitHub/token
      target: ~/.config/gh/token

  # Lifecycle scripts — hook into apply, reconcile, drift, and change events.
  # Each hook accepts a list of script entries. Entries can be simple strings
  # (command to run) or objects with run, timeout, and continueOnError fields.
  # optional
  scripts:
    # Scripts run before apply. Paths relative to config repo or inline commands.
    # optional, default: []
    preApply:
      - scripts/pre-setup.sh
    # Scripts run after apply.
    # optional, default: []
    postApply:
      - run: scripts/post-setup.sh
        timeout: 60s
        continueOnError: false
    # Scripts run before reconcile.
    # optional, default: []
    preReconcile:
      - scripts/reconcile-pre.sh
    # Scripts run after reconcile.
    # optional, default: []
    postReconcile:
      - scripts/reconcile-post.sh
    # Scripts run when drift is detected.
    # optional, default: []
    onDrift:
      - scripts/on-drift.sh
    # Scripts run when configuration changes.
    # optional, default: []
    onChange:
      - scripts/on-change.sh
"#;

const CONFIG_SCHEMA: &str = r#"# cfgd Config schema — cfgd.io/v1alpha1
# The root configuration file (cfgd.yaml). Entry point for cfgd.
# Tells cfgd which profile to activate, where config is stored, and how the daemon behaves.

apiVersion: cfgd.io/v1alpha1  # required, always this value
kind: Config                   # required, always "Config"

metadata:
  name: my-workstation         # required, string — config name (typically machine name)

spec:
  # Active profile name — the profile YAML file to activate (without .yaml extension).
  # required, string
  profile: work

  # Git origin(s) for the config repository. Can be a single object or a list.
  # optional, default: []
  origin:
    type: Git                  # required: "Git" or "Server"
    url: git@github.com:me/machine-config.git  # required, string — repository URL
    branch: master             # optional, string, default: "master"
    auth: ssh                  # optional, string — auth method hint

  # Daemon configuration — controls the background reconciliation loop.
  # optional
  daemon:
    enabled: true              # optional, bool, default: false

    # Reconciliation settings
    reconcile:
      # How often to check for drift (e.g. "1m", "5m", "1h").
      # optional, string, default: "5m"
      interval: 5m
      # Reconcile immediately when config files change (via file watcher).
      # optional, bool, default: false
      onChange: true
      # Auto-apply detected changes without prompting.
      # optional, bool, default: false
      autoApply: false
      # Drift reconciliation policy for daemon auto-reconciliation.
      # Values: Auto (silently apply), NotifyOnly (notify but don't apply, default), Prompt (future).
      # optional, default: NotifyOnly
      driftPolicy: NotifyOnly
      # Auto-apply policy — controls behavior for different change categories.
      # optional
      policy:
        newRecommended: Notify     # optional: Notify (default), Accept, Reject, Ignore
        newOptional: Ignore        # optional: Notify, Accept, Reject, Ignore (default)
        lockedConflict: Notify     # optional: Notify (default), Accept, Reject, Ignore
      # Per-module or per-profile reconcile overrides (kustomize-style patches).
      # Each patch targets a specific Module or Profile by name and overrides
      # individual reconcile fields. Precedence: Module patch > Profile patch > global.
      # optional, default: []
      patches:
        - kind: Module             # required: "Module" or "Profile"
          name: nvim               # optional, string — target name (omit to apply to all of this kind)
          interval: 1m             # optional, string — override interval
          autoApply: true          # optional, bool — override auto-apply
          driftPolicy: Auto        # optional: Auto, NotifyOnly, Prompt

    # Git sync settings
    sync:
      autoPull: true           # optional, bool, default: false — auto-pull from remote
      autoPush: false          # optional, bool, default: false — auto-commit and push local changes
      interval: 5m             # optional, string, default: "1h" — sync interval

    # Notification settings
    notify:
      drift: true              # optional, bool, default: false — notify on drift detection
      method: Desktop          # optional: Desktop (default), Stdout, Webhook
      webhookUrl: https://hooks.example.com/cfgd   # optional, string — webhook URL (when method=webhook)

    # Mirror daemon log into the Windows Event Log under the `cfgd` source
    # in addition to the default %LOCALAPPDATA%\cfgd\daemon.log file appender.
    # No effect on Unix. Read by `cfgd daemon install`; flipping the flag
    # requires `cfgd daemon uninstall && cfgd daemon install` to take effect.
    # optional, bool, default: false
    windowsEventLog: false

  # Secrets backend configuration.
  # optional
  secrets:
    backend: sops              # optional, string, default: "sops" — primary backend
    sops:
      ageKey: ~/.config/cfgd/age-key.txt   # optional, string — path to age key file
    # External secret provider integrations.
    # optional, default: []
    integrations:
      - name: 1password        # required, string — provider name (1password, bitwarden, vault)
      - name: bitwarden
      - name: vault

  # Multi-source config management — subscribe to team/org config sources.
  # optional, default: []
  sources:
    - name: acme-corp          # required, string — source name
      origin:
        type: Git              # required: "Git" or "Server"
        url: git@github.com:acme-corp/dev-config.git  # required, string
        branch: master         # optional, string, default: "master"
      subscription:
        profile: acme-backend  # optional, string — specific profile from source to subscribe to
        priority: 500          # optional, u32, default: 500 — merge priority (higher wins)
        acceptRecommended: true   # optional, bool, default: false — auto-accept recommended items
        optIn:                 # optional, list of strings — explicitly opt into optional items
          - extra-tools
        overrides: {}          # optional, YAML value — local overrides applied on top of source
        reject: {}             # optional, YAML value — items to reject from source
      sync:
        interval: 1h           # optional, string, default: "1h"
        autoApply: false       # optional, bool, default: false
        pinVersion: v1.2.3     # optional, string — pin to a specific source version

  # Theme configuration — controls terminal output styling.
  # Can be a string (theme name) or an object with name and overrides.
  # optional, default: "default"
  # String form: theme: dracula
  # Object form:
  theme:
    name: default              # optional, string, default: "default"
    overrides:                 # optional — override individual theme colors/icons
      header: cyan             # optional, string — color name
      success: green           # optional, string
      warning: yellow          # optional, string
      error: red               # optional, string
      info: blue               # optional, string
      muted: gray              # optional, string
      running: cyan            # optional, string — in-progress status color
      diffAdd: green           # optional, string
      diffRemove: red          # optional, string
      diffContext: gray        # optional, string
      iconOk: "✓"              # optional, string — icon character
      iconWarn: "⚠"            # optional, string
      iconFail: "✗"            # optional, string
      iconPending: "○"         # optional, string
      iconRunning: "◐"         # optional, string
      iconSkipped: "—"         # optional, string
      iconArrow: "→"           # optional, string

  # Module registries and security settings.
  # optional
  modules:
    # Git repos containing reusable modules in modules/<name>/module.yaml structure.
    # optional, default: []
    registries:
      - name: community        # required, string — short name / alias
        url: https://github.com/cfgd-community/modules.git  # required, string — git URL
    # Module security settings.
    # optional
    security:
      # Require GPG/SSH signatures on all remote module tags.
      # When true, unsigned modules are rejected unless --allow-unsigned is passed.
      # optional, bool, default: false
      requireSignatures: false

  # Global default file deployment strategy. Per-file overrides take precedence.
  # optional, default: Symlink
  # Values: Symlink, Copy, Template, Hardlink
  fileStrategy: Symlink

  # Security settings for source signature verification.
  # optional
  security:
    # Allow unsigned source content even when the source requires signed commits.
    # Intended for development/testing environments.
    # optional, bool, default: false
    allowUnsigned: false

  # CLI command aliases — map of alias name to command string.
  # Built-in defaults (add, remove) can be overridden or extended.
  # optional, default: {}
  aliases:
    add: "profile update --file"
    remove: "profile update --file"
    up: "apply --yes"
    s: status
    pkg: "profile update --package"

  # AI assistant configuration for cfgd generate.
  # optional
  ai:
    # AI provider to use.
    # optional, string, default: "claude"
    provider: claude
    # Model name/ID.
    # optional, string, default: "claude-sonnet-4-6"
    model: claude-sonnet-4-6
    # Environment variable name containing the API key.
    # optional, string, default: "ANTHROPIC_API_KEY"
    apiKeyEnv: ANTHROPIC_API_KEY
"#;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn all_schemas_are_non_empty_valid_yaml() {
        for kind in [SchemaKind::Module, SchemaKind::Profile, SchemaKind::Config] {
            let schema = get_schema(kind);
            assert!(!schema.is_empty(), "{kind:?} schema is empty");
            let _: serde_yaml::Value = serde_yaml::from_str(schema)
                .unwrap_or_else(|e| panic!("{kind:?} schema is not valid YAML: {e}"));
            assert!(
                schema.contains("apiVersion"),
                "{kind:?} schema missing apiVersion"
            );
        }
    }
}
