{ lib }:

let
  cisco = import ./cisco-base.nix { inherit lib; };
in {
  desktopSize   = "640x480x24";
  thumbnailSize = "123x111";

  # Return a list of { name, content } provisioning files for this phone.
  # provisioning/default.nix wraps each with pkgs.writeText for the linkFarm.
  mkFiles =
    { mac, label, displayName, password, serverAddress, ntpServer
    , sipPort       ? 5060
    , directoryPort ? 8080
    , familyLineEnabled  ? false
    , familyLineLabel    ? "Familie"
    , familyLinePassword ? ""
    , intercomEnabled    ? false
    , intercomPassword   ? ""
    , intercomLineIndex  ? 2
    , allExtensions      ? []
    , allStarExtensions  ? []
    , hasTrunk           ? false
    , hasIntercomButton  ? false
    , pageExtension      ? null
    }:
    let
      # Line button assignments:
      #   button 1 / lineIndex 1 — personal/location L1 line (always present)
      #   button 2 / lineIndex 2 — family L2 line       (when familyLineEnabled)
      #   button N / lineIndex N — intercom              (when intercomEnabled; N = 2 or 3)
      intercomButton = if familyLineEnabled then 3 else 2;

      dialplanFile = cisco.dialplanFilename mac;

      configXml = ''
      <?xml version="1.0" encoding="UTF-8"?>
      <device>
         <deviceProtocol>SIP</deviceProtocol>
         <sshUserId>admin</sshUserId>
         <sshPassword>password</sshPassword>
         <devicePool>
            <dateTimeSetting>
               <dateTemplate>D.M.YA</dateTemplate>
               <timeZone>Central Europe Standard/Daylight Time</timeZone>
               <ntps>
                  <ntp>
                     <name>${ntpServer}</name>
                  </ntp>
               </ntps>
            </dateTimeSetting>
            <callManagerGroup>
               <members>
                  <member priority="0">
                     <callManager>
                        <ports>
                           <sipPort>${toString sipPort}</sipPort>
                        </ports>
                        <processNodeName>${serverAddress}</processNodeName>
                     </callManager>
                  </member>
               </members>
            </callManagerGroup>
         </devicePool>
         <sipProfile>
            <sipProxies>
               <backupProxy></backupProxy>
               <backupProxyPort>5060</backupProxyPort>
               <emergencyProxy></emergencyProxy>
               <emergencyProxyPort></emergencyProxyPort>
               <outboundProxy></outboundProxy>
               <outboundProxyPort></outboundProxyPort>
               <registerWithProxy>true</registerWithProxy>
            </sipProxies>
            <sipCallFeatures>
               <cnfJoinEnabled>true</cnfJoinEnabled>
               <callForwardURI>x-serviceuri-cfwdall</callForwardURI>
               <callPickupURI>x-cisco-serviceuri-pickup</callPickupURI>
               <callPickupListURI>x-cisco-serviceuri-opickup</callPickupListURI>
               <callPickupGroupURI>x-cisco-serviceuri-gpickup</callPickupGroupURI>
               <meetMeServiceURI>x-cisco-serviceuri-meetme</meetMeServiceURI>
               <abbreviatedDialURI>x-cisco-serviceuri-abbrdial</abbreviatedDialURI>
               <callHoldRingback>2</callHoldRingback>
               <anonymousCallBlock>2</anonymousCallBlock>
               <callerIdBlocking>2</callerIdBlocking>
               <dndControl>0</dndControl>
               <remoteCcEnable>true</remoteCcEnable>
            </sipCallFeatures>
            <sipStack>
               <sipInviteRetx>6</sipInviteRetx>
               <sipRetx>10</sipRetx>
               <timerInviteExpires>180</timerInviteExpires>
               <timerRegisterExpires>3600</timerRegisterExpires>
               <timerRegisterDelta>5</timerRegisterDelta>
               <timerKeepAliveExpires>120</timerKeepAliveExpires>
               <timerSubscribeExpires>120</timerSubscribeExpires>
               <timerSubscribeDelta>5</timerSubscribeDelta>
               <timerT1>500</timerT1>
               <timerT2>4000</timerT2>
               <maxRedirects>70</maxRedirects>
               <remotePartyID>false</remotePartyID>
               <userInfo>None</userInfo>
            </sipStack>
            <transferOnhookEnabled>false</transferOnhookEnabled>
            <kpml>3</kpml>
            <phoneLabel>${(builtins.substring 0 12 label)}</phoneLabel>
            <stutterMsgWaiting>1</stutterMsgWaiting>
            <callStats>false</callStats>
            <sipLines>
               <line button="1" lineIndex="1">
                  <featureID>9</featureID>
                  <featureLabel>${displayName}</featureLabel>
                  <proxy>USECALLMANAGER</proxy>
                  <port>${toString sipPort}</port>
                  <name>${mac}</name>
                  <displayName>${displayName}</displayName>
                  <autoAnswer>
                     <autoAnswerEnabled>2</autoAnswerEnabled>
                  </autoAnswer>
                  <callWaiting>3</callWaiting>
                  <authName>${mac}</authName>
                  <authPassword>${password}</authPassword>
                  <messageWaitingLampPolicy>1</messageWaitingLampPolicy>
                  <messagesNumber>*97</messagesNumber>
                  <contact>${mac}</contact>
                  <forwardCallInfoDisplay>
                     <callerName>true</callerName>
                     <callerNumber>true</callerNumber>
                     <redirectedNumber>true</redirectedNumber>
                     <dialedNumber>true</dialedNumber>
                  </forwardCallInfoDisplay>
               </line>
      ${if familyLineEnabled then ''
               <line button="2" lineIndex="2">
                  <featureID>9</featureID>
                  <featureLabel>${familyLineLabel}</featureLabel>
                  <proxy>USECALLMANAGER</proxy>
                  <port>${toString sipPort}</port>
                  <name>${mac}-l2</name>
                  <displayName>${familyLineLabel}</displayName>
                  <autoAnswer>
                     <autoAnswerEnabled>2</autoAnswerEnabled>
                  </autoAnswer>
                  <callWaiting>3</callWaiting>
                  <authName>${mac}-l2</authName>
                  <authPassword>${familyLinePassword}</authPassword>
                  <messageWaitingLampPolicy>3</messageWaitingLampPolicy>
                  <messagesNumber>*97</messagesNumber>
                  <contact>${mac}-l2</contact>
                  <forwardCallInfoDisplay>
                     <callerName>true</callerName>
                     <callerNumber>true</callerNumber>
                     <redirectedNumber>true</redirectedNumber>
                     <dialedNumber>true</dialedNumber>
                  </forwardCallInfoDisplay>
               </line>
      '' else ""}${if intercomEnabled then ''
               <line button="${toString intercomButton}" lineIndex="${toString intercomButton}">
                  <featureID>23</featureID>
                  <featureLabel>Intercom</featureLabel>
                  <proxy>USECALLMANAGER</proxy>
                  <port>${toString sipPort}</port>
                  <name>${mac}-intercom</name>
                  <displayName>Intercom</displayName>
                  <autoAnswer>
                     <autoAnswerEnabled>3</autoAnswerEnabled>
                     <autoAnswerMode>Auto Answer with Speakerphone</autoAnswerMode>
                  </autoAnswer>
                  <callWaiting>3</callWaiting>
                  <authName>${mac}-intercom</authName>
                  <authPassword>${intercomPassword}</authPassword>
                  <maxNumCalls>1</maxNumCalls>
                  <busyTrigger>1</busyTrigger>
                  <contact>${mac}-intercom</contact>
               </line>
      '' else ""}      </sipLines>
            <voipControlPort>${toString sipPort}</voipControlPort>
            <startMediaPort>16348</startMediaPort>
            <stopMediaPort>20134</stopMediaPort>
            <dscpForAudio>184</dscpForAudio>
            <dialTemplate>${dialplanFile}</dialTemplate>
         </sipProfile>
          <MissedCallLoggingOption>1</MissedCallLoggingOption>
         <commonProfile>
            <phonePassword></phonePassword>
            <backgroundImageAccess>true</backgroundImageAccess>
            <callLogBlfEnabled>2</callLogBlfEnabled>
         </commonProfile>
         <loadInformation>sip8961.9-4-2ES-14</loadInformation>
         <vendorConfig>
            <webAccess>0</webAccess>
            <settingsAccess>1</settingsAccess>
            <autoSelectLineEnable>0</autoSelectLineEnable>
            <loggingDisplay>1</loggingDisplay>
            <daysDisplayNotActive>1,2,3,4,5,6,7</daysDisplayNotActive>
            <sshAccess>0</sshAccess>
            <displayOnTime>00:00</displayOnTime>
            <displayOnDuration>00:00</displayOnDuration>
            <displayIdleTimeout>00:05</displayIdleTimeout>
            <displayOnWhenIncomingCall>1</displayOnWhenIncomingCall>
         </vendorConfig>
         <userLocale>
            <langCode>en_US</langCode>
            <winCharSet>utf-8</winCharSet>
         </userLocale>
         <deviceSecurityMode>1</deviceSecurityMode>
         <authenticationURL></authenticationURL>
         <directoryURL>http://${serverAddress}:${toString directoryPort}/directory.xml</directoryURL>
         <messagesURL />
         <servicesURL></servicesURL>
         <idleURL></idleURL>
         <informationURL></informationURL>
         <phoneServices useHTTPS="false">
            <provisioning>2</provisioning>
            <phoneService type="1" category="0">
              <name>Missed Calls</name>
              <url>Application:Cisco/MissedCalls</url>
              <vendor></vendor>
              <version></version>
            </phoneService>
            <phoneService type="1" category="0">
              <name>Received Calls</name>
              <url>Application:Cisco/ReceivedCalls</url>
              <vendor></vendor>
              <version></version>
            </phoneService>
            <phoneService type="1" category="0">
              <name>Placed Calls</name>
              <url>Application:Cisco/PlacedCalls</url>
              <vendor></vendor>
              <version></version>
            </phoneService>
            <phoneService type="2" category="0">
              <name>Voicemail</name>
              <url>Application:Cisco/Voicemail</url>
              <vendor></vendor>
              <version></version>
            </phoneService>
         </phoneServices>
         <proxyServerURL></proxyServerURL>
         <transportLayerProtocol>1</transportLayerProtocol>
         <capfAuthMode>0</capfAuthMode>
         <capfList>
            <capf>
               <phonePort>3804</phonePort>
            </capf>
         </capfList>
         <encrConfig>false</encrConfig>
      </device>
      '';

      # Dial template: the phone tests patterns top-to-bottom and dials as soon
      # as digits match a pattern with timeout="0", or after the timeout for
      # timeout > 0.  Explicit patterns must come before the catch-all.
      h = builtins.hashString "sha256" (builtins.toJSON {
        inherit mac allExtensions allStarExtensions hasTrunk hasIntercomButton intercomLineIndex;
      });
      versionStamp = "${builtins.substring 0 8 h}-${builtins.substring 8 4 h}-${builtins.substring 12 4 h}-${builtins.substring 16 4 h}-${builtins.substring 20 12 h}";
      extMatch = ext: "  <TEMPLATE match=\"${ext}\" timeout=\"0\" />";

      dialplanXml = ''
      <dialTemplate>
        <versionStamp>${versionStamp}</versionStamp>
      ${lib.optionalString hasIntercomButton
        "  <TEMPLATE match=\"\" timeout=\"0\" rewrite=\"${pageExtension}\" line=\"${toString intercomLineIndex}\" />"}
      ${lib.concatMapStrings (ext: extMatch ext + "\n") allExtensions}
      ${lib.concatMapStrings (ext: extMatch ext + "\n") allStarExtensions}
        <TEMPLATE match=".." timeout="5" />
      </dialTemplate>
      '';

    in [
      { name = cisco.configFilename mac;   content = configXml; }
      { name = cisco.dialplanFilename mac; content = dialplanXml; }
    ];
}
