{ lib, pkgs, cfg, templates, allPhones }:

let
  # Collect unique (desktopSize, thumbnailSize) pairs from provisioned phone models
  sizeConfigs = lib.unique (
    lib.concatLists (lib.mapAttrsToList (_: phone:
      if lib.hasAttr phone.model templates
        then let t = templates.${phone.model}; in
          [{ desktop = t.desktopSize; thumbnail = t.thumbnailSize; }]
        else []
    ) allPhones));

  # Parse "WxH" or "WxHxD" into width and height
  parseDimensions = size:
    let parts = lib.splitString "x" size;
    in { w = lib.elemAt parts 0; h = lib.elemAt parts 1; };

  # Build a resized image derivation
  resizeImage = { src, width, height, name }:
    pkgs.runCommand name { nativeBuildInputs = [ pkgs.imagemagick ]; } ''
      convert "${src}" -resize ${width}x${height}! -strip PNG24:$out
    '';

in lib.concatMap (sc:
  let
    size = sc.desktop;
    dim  = parseDimensions size;
    tn   = parseDimensions sc.thumbnail;
    listXml = ''
      <CiscoIPPhoneImageList>
    '' + lib.concatStringsSep "\n" (lib.imap1 (i: name: ''
        <ImageItem Image="TFTP:Desktops/${size}/tn-${toString i}.png" URL="TFTP:Desktops/${size}/bg-${toString i}.png"/>
      '') (lib.attrNames cfg.backgroundImages))
    + ''
      </CiscoIPPhoneImageList>
    '';
    listFile = pkgs.writeText "List.xml" listXml;
  in
    [{ name = "Desktops/${size}/List.xml"; path = listFile; }]
    ++ lib.concatLists (lib.imap1 (i: name:
      let src = cfg.backgroundImages.${name}; in [
        { name = "Desktops/${size}/bg-${toString i}.png";
          path = resizeImage { inherit src; width = dim.w; height = dim.h; name = "bg-${toString i}.png"; }; }
        { name = "Desktops/${size}/tn-${toString i}.png";
          path = resizeImage { inherit src; width = tn.w; height = tn.h; name = "tn-${toString i}.png"; }; }
      ]
    ) (lib.attrNames cfg.backgroundImages))
) sizeConfigs
