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

let
  baseUrl = "http://${cfg.serverAddress}:${toString cfg.directoryPort}";

  hasPageExtensions = lib.any (e: e.mode == "page") (lib.attrValues cfg.extensions);
  hasPhonebook      = cfg.phonebook != [];

  # Deduplicated directory entries: one per extension, using the displayName from
  # allPhones (all phones sharing an extension have the same displayName).
  extensionEntries =
    lib.attrValues (lib.foldlAttrs (acc: _key: phone:
      if lib.hasAttr phone.extension acc || phone.displayName == "" then acc
      else acc // { ${phone.extension} = { inherit (phone) extension displayName; }; }
    ) {} allPhones);

  menuXml = ''
    <?xml version="1.0" encoding="UTF-8"?>
    <CiscoIPPhoneMenu>
     <Title>${cfg.directoryName} Telefonbuch</Title>
     <Prompt>Ihre Wahl</Prompt>
     <MenuItem>
      <Name>Internes Telefonbuch</Name>
      <URL>${baseUrl}/directory-list.xml</URL>
     </MenuItem>
  '' + lib.optionalString (intercomEntries != [] || hasPageExtensions) ''
     <MenuItem>
      <Name>Intercom / Durchsage</Name>
      <URL>${baseUrl}/intercom.xml</URL>
     </MenuItem>
  '' + lib.optionalString hasPhonebook ''
     <MenuItem>
      <Name>Externes Telefonbuch</Name>
      <URL>${baseUrl}/phonebook.xml</URL>
     </MenuItem>
  '' + ''
    </CiscoIPPhoneMenu>
  '';

  listXml = ''
    <?xml version="1.0" encoding="UTF-8"?>
    <CiscoIPPhoneDirectory>
     <Title>${cfg.directoryName} Telefonbuch</Title>
     <Prompt>Ihre Wahl</Prompt>
  '' + lib.concatMapStringsSep "\n" (e: ''
     <DirectoryEntry>
      <Name>${e.displayName}</Name>
      <Telephone>${e.extension}</Telephone>
     </DirectoryEntry>
  '') extensionEntries
  + ''
    </CiscoIPPhoneDirectory>
  '';

  intercomXml = ''
    <?xml version="1.0" encoding="UTF-8"?>
    <CiscoIPPhoneDirectory>
     <Title>Intercom / Durchsage</Title>
     <Prompt>Ihre Wahl</Prompt>
  '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (ext: extCfg:
    lib.optionalString (extCfg.mode == "page" && extCfg.displayName != "") ''
     <DirectoryEntry>
      <Name>${extCfg.displayName}</Name>
      <Telephone>${ext}</Telephone>
     </DirectoryEntry>
    '') cfg.extensions)
  + lib.concatMapStringsSep "\n" (ic: ''
     <DirectoryEntry>
      <Name>${ic.displayName}</Name>
      <Telephone>${ic.extension}</Telephone>
     </DirectoryEntry>
  '') intercomEntries
  + ''
    </CiscoIPPhoneDirectory>
  '';

  phonebookMenuXml = ''
    <?xml version="1.0" encoding="UTF-8"?>
    <CiscoIPPhoneMenu>
     <Title>Externes Telefonbuch</Title>
     <Prompt>Bitte wählen</Prompt>
  '' + lib.concatStringsSep "\n" (lib.imap0 (i: contact: ''
     <MenuItem>
      <Name>${contact.name}</Name>
      <URL>${baseUrl}/phonebook-${toString i}.xml</URL>
     </MenuItem>
  '') cfg.phonebook)
  + ''
    </CiscoIPPhoneMenu>
  '';

  mkContactXml = contact: ''
    <?xml version="1.0" encoding="UTF-8"?>
    <CiscoIPPhoneDirectory>
     <Title>${contact.name}</Title>
     <Prompt>Bitte wählen</Prompt>
  '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (label: number: ''
     <DirectoryEntry>
      <Name>${label}</Name>
      <Telephone>${number}</Telephone>
     </DirectoryEntry>
  '') contact.numbers)
  + ''
    </CiscoIPPhoneDirectory>
  '';

in {
  menuFile      = pkgs.writeText "directory.xml"      menuXml;
  listFile      = pkgs.writeText "directory-list.xml" listXml;
  intercomFile  = pkgs.writeText "intercom.xml"       intercomXml;
  phonebookMenuFile    = pkgs.writeText "phonebook.xml" phonebookMenuXml;
  phonebookDetailFiles = lib.imap0 (i: contact:
    pkgs.writeText "phonebook-${toString i}.xml" (mkContactXml contact)
  ) cfg.phonebook;
}
