{{define "device_assignments"}}
<div class="card assignment-board-page">
  <div class="section-title">
    <div>
      <h2 class="title-with-icon">{{icon "devices"}}<span>通道部署</span></h2>
    </div>
  </div>

  {{if .DeviceAssignmentBoard}}
  <div class="assignment-kpis">
    <div class="assignment-kpi">
      <span>视频通道</span>
      <strong>{{.DeviceAssignmentBoard.Stats.TotalUnits}}</strong>
    </div>
    <div class="assignment-kpi">
      <span>设备</span>
      <strong>{{.DeviceAssignmentBoard.Stats.TotalDevices}}</strong>
    </div>
    <div class="assignment-kpi">
      <span>已分配</span>
      <strong>{{.DeviceAssignmentBoard.Stats.AssignedUnits}}</strong>
    </div>
    <div class="assignment-kpi">
      <span>未分配</span>
      <strong>{{.DeviceAssignmentBoard.Stats.UnassignedUnits}}</strong>
    </div>
    <div class="assignment-kpi">
      <span>平均负载</span>
      <strong>{{printf "%.1f" .DeviceAssignmentBoard.Stats.AverageLoad}}</strong>
    </div>
    <div class="assignment-kpi">
      <span>满载设备</span>
      <strong>{{.DeviceAssignmentBoard.Stats.OverloadedDevices}}</strong>
    </div>
  </div>

  <form method="post" action="/ui/device-assignments" id="assignment-board-form">
    <input type="hidden" name="board_state_json" id="assignment-board-state" value="" />
    <div class="assignment-action-bar">
      <label class="assignment-slider">
        <span>每台最多</span>
        <input type="range" min="1" max="8" step="1" value="{{.MaxUnitsPerDevice}}" id="max-units-range" name="max_units_per_device" />
        <strong id="max-units-value">{{.MaxUnitsPerDevice}} 路/台</strong>
      </label>
      <div class="actions compact">
        <button type="button" class="btn secondary" id="auto-assign-btn">自动平均分配</button>
        <button type="button" class="btn secondary" id="clear-assign-btn">清空分配</button>
        <button type="submit">保存通道部署</button>
      </div>
    </div>

    <div id="assignment-feedback" class="form-hint"></div>

    <div class="assignment-board-grid" id="assignment-cards">
      {{range .DeviceAssignmentBoard.Cards}}
      <section class="assignment-device-card state-{{.Status}}" data-device-card="{{.DeviceID}}">
        <div class="assignment-device-head">
          <div>
            <h3>{{.DeviceName}}</h3>
            <span class="mono">{{.DeviceID}}</span>
          </div>
          <div class="assignment-device-metrics">
            <strong>{{.AssignedCount}} / {{.MaxUnits}}</strong>
            <span class="pill">{{.Status}}</span>
          </div>
        </div>
        <div class="assignment-chip-list" data-assigned-list="{{.DeviceID}}">
          {{range .Units}}
          <span class="assignment-chip" data-unit-ref="{{.Ref}}">
            <span class="assignment-chip-text">{{if .DisplayName}}{{.DisplayName}}{{else}}{{.Name}}{{end}}</span>
            <button type="button" class="assignment-chip-remove" data-remove-unit="{{.Ref}}">×</button>
          </span>
          {{end}}
        </div>
        {{if lt .AssignedCount .MaxUnits}}
        <div class="assignment-device-add">
          <select data-add-select="{{.DeviceID}}">
            <option value="">添加视频通道</option>
          </select>
          <button type="button" class="btn secondary" data-add-button="{{.DeviceID}}">加入</button>
        </div>
        {{end}}
      </section>
      {{end}}
    </div>

    <section class="assignment-unassigned">
      <div class="section-title compact">
        <div>
          <h3>未部署视频通道</h3>
        </div>
      </div>
      <div class="assignment-chip-list" id="assignment-unassigned-list">
        {{range .DeviceAssignmentBoard.Unassigned}}
        <span class="assignment-chip assignment-chip-unassigned" data-unit-ref="{{.Ref}}">
          <span class="assignment-chip-text">{{if .DisplayName}}{{.DisplayName}}{{else}}{{.Name}}{{end}}</span>
        </span>
        {{else}}
        <div class="empty-state compact"><div class="empty-title">已全部分配</div></div>
        {{end}}
      </div>
    </section>
  </form>

  <script type="application/json" id="assignment-board-seed">{{.DeviceAssignmentBoardJSON}}</script>
  <script>
    (() => {
      const seedEl = document.getElementById('assignment-board-seed');
      if (!seedEl) return;
      const seed = JSON.parse(seedEl.textContent || '{}');
      const state = {
        max: Number(seed.max_units_per_device || {{.MaxUnitsPerDevice}}),
        units: {},
        devices: {},
        meta: {}
      };
      (seed.cards || []).forEach(card => {
        state.meta[card.device_id] = {
          device_id: card.device_id,
          device_name: card.device_name,
          max_units: card.max_units || state.max
        };
        state.devices[card.device_id] = (card.units || []).map(unit => {
          state.units[unit.ref] = unit;
          return unit.ref;
        });
      });
      (seed.unassigned || []).forEach(unit => {
        state.units[unit.ref] = unit;
      });

      const maxRange = document.getElementById('max-units-range');
      const maxValue = document.getElementById('max-units-value');
      const feedback = document.getElementById('assignment-feedback');
      const hiddenState = document.getElementById('assignment-board-state');
      const cardsContainer = document.getElementById('assignment-cards');
      const unassignedContainer = document.getElementById('assignment-unassigned-list');
      const form = document.getElementById('assignment-board-form');

      function unitLabel(unit) {
        return unit.display_name || unit.name;
      }

      function statusFor(count) {
        if (count <= 0) return 'idle';
        if (count >= state.max) return 'full';
        if (count * 2 >= state.max) return 'busy';
        return 'low';
      }

      function statusRank(status) {
        return { full: 0, busy: 1, low: 2, idle: 3 }[status] ?? 4;
      }

      function allRefs() {
        return Object.keys(state.units).sort((a, b) => {
          const ua = state.units[a];
          const ub = state.units[b];
          if ((ua.scene_template_name || '') !== (ub.scene_template_name || '')) {
            return (ua.scene_template_name || '').localeCompare(ub.scene_template_name || '');
          }
          return (ua.name || '').localeCompare(ub.name || '');
        });
      }

      function assignedRefSet() {
        const seen = new Set();
        Object.values(state.devices).forEach(refs => refs.forEach(ref => seen.add(ref)));
        return seen;
      }

      function unassignedRefs() {
        const assigned = assignedRefSet();
        return allRefs().filter(ref => !assigned.has(ref));
      }

      function currentProfile(deviceID) {
        const refs = state.devices[deviceID] || [];
        if (!refs.length) return '';
        const unit = state.units[refs[0]];
        return unit ? (unit.scene_template_name || '') : '';
      }

      function moveToUnassigned(ref) {
        Object.keys(state.devices).forEach(deviceID => {
          state.devices[deviceID] = (state.devices[deviceID] || []).filter(item => item !== ref);
        });
      }

      function addToDevice(deviceID, ref) {
        if (!deviceID || !ref) return;
        moveToUnassigned(ref);
        if (!state.devices[deviceID]) state.devices[deviceID] = [];
        state.devices[deviceID].push(ref);
      }

      function clearAssignments() {
        Object.keys(state.devices).forEach(deviceID => {
          state.devices[deviceID] = [];
        });
      }

      function autoAssign() {
        clearAssignments();
        const deviceIDs = Object.keys(state.devices).sort();
        const units = allRefs().map(ref => state.units[ref]);
        units.forEach(unit => {
          let target = null;
          deviceIDs.forEach(deviceID => {
            const refs = state.devices[deviceID] || [];
            const profile = currentProfile(deviceID);
            if (profile && profile !== unit.scene_template_name) return;
            if (refs.length >= state.max) return;
            if (!target || refs.length < (state.devices[target] || []).length) {
              target = deviceID;
            }
          });
          if (target) {
            state.devices[target].push(unit.ref);
          }
        });
        const remaining = unassignedRefs().length;
        feedback.textContent = `已按每台最多 ${state.max} 路完成自动分配${remaining > 0 ? `，剩余 ${remaining} 路未分配。` : '。'}`;
        render();
      }

      function syncHiddenState() {
        hiddenState.value = JSON.stringify({ devices: state.devices });
      }

      function renderStats() {
        const assigned = assignedRefSet();
        const totalUnits = allRefs().length;
        const totalDevices = Object.keys(state.devices).length;
        const average = totalDevices ? (assigned.size / totalDevices).toFixed(1) : '0.0';
        const full = Object.keys(state.devices).filter(deviceID => statusFor((state.devices[deviceID] || []).length) === 'full').length;
        const values = document.querySelectorAll('.assignment-kpi strong');
        if (values.length >= 6) {
          values[0].textContent = totalUnits;
          values[1].textContent = totalDevices;
          values[2].textContent = assigned.size;
          values[3].textContent = totalUnits - assigned.size;
          values[4].textContent = average;
          values[5].textContent = full;
        }
      }

      function renderCards() {
        const cards = Object.keys(state.devices).map(deviceID => {
          const refs = state.devices[deviceID] || [];
          return {
            deviceID,
            deviceName: (state.meta[deviceID] && state.meta[deviceID].device_name) || deviceID,
            refs,
            status: statusFor(refs.length)
          };
        }).sort((a, b) => {
          const rankDiff = statusRank(a.status) - statusRank(b.status);
          if (rankDiff !== 0) return rankDiff;
          if (b.refs.length !== a.refs.length) return b.refs.length - a.refs.length;
          return a.deviceID.localeCompare(b.deviceID);
        });

        cardsContainer.innerHTML = '';
        cards.forEach(card => {
          const section = document.createElement('section');
          section.className = `assignment-device-card state-${card.status}`;
          const currentTemplate = currentProfile(card.deviceID);
          const availableRefs = unassignedRefs().filter(ref => {
            const unit = state.units[ref];
            return !currentTemplate || unit.scene_template_name === currentTemplate;
          });
          const addControls = card.refs.length < state.max ? `
            <div class="assignment-device-add">
              <select data-add-select="${card.deviceID}">
                <option value="">添加视频通道</option>
                ${availableRefs.map(ref => `<option value="${ref}">${unitLabel(state.units[ref])}</option>`).join('')}
              </select>
              <button type="button" class="btn secondary" data-add-button="${card.deviceID}">加入</button>
            </div>
          ` : '';
          section.innerHTML = `
            <div class="assignment-device-head">
              <div>
                <h3>${card.deviceName}</h3>
                <span class="mono">${card.deviceID}</span>
              </div>
              <div class="assignment-device-metrics">
                <strong>${card.refs.length} / ${state.max}</strong>
                <span class="pill">${card.status}</span>
              </div>
            </div>
            <div class="assignment-chip-list"></div>
            ${addControls}
          `;
          const chipList = section.querySelector('.assignment-chip-list');
          card.refs.forEach(ref => {
            const unit = state.units[ref];
            const chip = document.createElement('span');
            chip.className = 'assignment-chip';
            chip.innerHTML = `<span class="assignment-chip-text">${unitLabel(unit)}</span><button type="button" class="assignment-chip-remove" data-remove-unit="${ref}">×</button>`;
            chipList.appendChild(chip);
          });
          cardsContainer.appendChild(section);
        });
      }

      function renderUnassigned() {
        const refs = unassignedRefs();
        if (!refs.length) {
          unassignedContainer.innerHTML = '<div class="empty-state compact"><div class="empty-title">已全部分配</div></div>';
          return;
        }
        unassignedContainer.innerHTML = '';
        refs.forEach(ref => {
          const unit = state.units[ref];
          const chip = document.createElement('span');
          chip.className = 'assignment-chip assignment-chip-unassigned';
          chip.innerHTML = `<span class="assignment-chip-text">${unitLabel(unit)}</span>`;
          unassignedContainer.appendChild(chip);
        });
      }

      function render() {
        maxValue.textContent = `${state.max} 路/台`;
        renderStats();
        renderCards();
        renderUnassigned();
        syncHiddenState();
      }

      maxRange.addEventListener('input', () => {
        state.max = Number(maxRange.value || state.max);
        render();
      });

      document.addEventListener('click', (event) => {
        const remove = event.target.closest('[data-remove-unit]');
        if (remove) {
          moveToUnassigned(remove.getAttribute('data-remove-unit'));
          feedback.textContent = '';
          render();
          return;
        }
        const add = event.target.closest('[data-add-button]');
        if (add) {
          const deviceID = add.getAttribute('data-add-button');
          const select = document.querySelector(`[data-add-select="${deviceID}"]`);
          if (select && select.value) {
            addToDevice(deviceID, select.value);
            feedback.textContent = '';
            render();
          }
          return;
        }
      });

      document.getElementById('auto-assign-btn').addEventListener('click', autoAssign);
      document.getElementById('clear-assign-btn').addEventListener('click', () => {
        clearAssignments();
        feedback.textContent = '已清空当前页面中的通道部署。';
        render();
      });
      form.addEventListener('submit', syncHiddenState);
      render();
    })();
  </script>
  {{else}}
  <div class="empty-state compact"><div class="empty-title">暂无可用的通道部署数据</div></div>
  {{end}}
</div>
{{end}}
