# lib/mkHome.nix — Compose a complete home-manager configuration.
#
# This is the central function that replaces the old mkHomeConfig from nixos-config.
# It assembles imports based on three dimensions:
#
#   WHO you are  →  user + identity (preferences + git/ssh/jj config)
#   WHAT you do  →  context (desktop|server) + sets (coding, gaming, media)
#   WHERE you are →  host (handled by nixos-config, only overrides here)
#
# Usage:
#   imports = [ (m3ta-lib.mkHome {
#     user = "m3tam3re";
#     identity = "private";     # or "work"
#     context = "desktop";      # or "server"
#     sets = [ "coding" "gaming" "media" ];
#   }) ];
#
# Then override host-specific settings in the consuming module:
#   m3ta.home.sets.coding.languages.python.extra = true;
#   wayland.windowManager.hyprland.settings.monitor = [ ... ];
#
{
  inputs,
  selfPath,
}: let
  lib = inputs.nixpkgs.lib;
in {
  mkHome = {
    user ? "m3tam3re",
    identity ? "private",
    context ? null,
    sets ? [],
  }: let
    # --- Module path helpers ---
    profilePath = ../profiles;
    userPath = ../users;

    # Always loaded — CLI tools, shell, secrets, overlays
    baseModule = "${profilePath}/base";

    # Context modules — mutually exclusive (desktop or server)
    contextModuleMap = {
      desktop = "${profilePath}/contexts/desktop";
      server = "${profilePath}/contexts/server";
    };

    # Feature sets — freely combinable, some have context guards
    setModuleMap = {
      coding = "${profilePath}/sets/coding";
      gaming = "${profilePath}/sets/gaming";
      media = "${profilePath}/sets/media";
    };

    # Sets that require desktop context
    desktopOnlySets = ["gaming" "media"];

    # User preferences — always loaded (shell style, editor config, etc.)
    preferencesPath = "${userPath}/${user}/preferences";

    # Identity — git name/email, SSH match blocks, jj config
    identityPath = "${userPath}/${user}/identities/${identity}.nix";

    # Resolve context module
    contextImport =
      if context == null
      then []
      else if builtins.hasAttr context contextModuleMap
      then [contextModuleMap.${context}]
      else throw "m3ta-home: unknown context '${context}'. Valid: desktop, server";

    # Resolve set modules
    setImports =
      map
      (s:
        if builtins.hasAttr s setModuleMap
        then setModuleMap.${s}
        else throw "m3ta-home: unknown set '${s}'. Valid: ${lib.concatStringsSep ", " (builtins.attrNames setModuleMap)}")
      sets;

    # Validation: desktop-only sets
    usedDesktopOnlySets =
      builtins.filter (s: builtins.elem s desktopOnlySets) sets;
  in {
    imports =
      [
        # External Home Manager modules required by selectable profiles
        inputs.agent-lib.homeManagerModules.default
        inputs.dms.homeModules.default
        inputs.dms-plugin-registry.homeModules.default

        # Paths module — must be first, provides m3taHome.paths.srcRoot
        ../modules/paths.nix
        baseModule
        preferencesPath
        identityPath
      ]
      ++ contextImport
      ++ setImports;

    # Set the flake source root for asset path resolution
    "m3ta-home".paths.srcRoot = selfPath;

    assertions =
      [
        {
          assertion = builtins.elem context ["desktop" "server" null];
          message = "m3ta-home: context must be 'desktop', 'server', or null (got: '${toString context}')";
        }
      ]
      ++ map (s: {
        assertion = context == "desktop";
        message = "m3ta-home: set '${s}' requires context = 'desktop'";
      })
      usedDesktopOnlySets;
  };
}
