export function segmentStateKey(trackName, trackId, segmentIdentity) {
  return trackId
    ? `${trackName}_${trackId}_${segmentIdentity}`
    : `${trackName}_${segmentIdentity}`;
}

export function ensureSegmentIdentity(segment, track, index) {
  if (segment?.id != null && String(segment.id).trim()) return String(segment.id);
  const trackIdentity = String(track?.id || 'track').replaceAll(/\s+/g, '-');
  const type = String(track?.type || 'clip').replaceAll(/\s+/g, '-');
  const identity = `${type}-${trackIdentity}-${index}`;
  if (segment) segment.id = identity;
  return identity;
}

export function stableSegmentStateKey(trackName, trackId, segment, index = 0) {
  const identity = ensureSegmentIdentity(segment, { id: trackId, type: trackName }, index);
  return segmentStateKey(trackName, trackId, `id_${identity}`);
}

export function legacyTrackName(trackType) {
  if (trackType === 'media') return 'images';
  if (trackType === 'text') return 'texts';
  if (trackType === 'postfx') return 'postfx';
  return `${trackType}s`;
}

function moveEntry(store, oldKey, newKey) {
  if (!Object.hasOwn(store, oldKey)) return;
  store[newKey] = store[oldKey];
  delete store[oldKey];
}

export function removeIndexedSegmentState(stores, trackName, trackId, deletedIndex, segmentCount) {
  const deletedKey = segmentStateKey(trackName, trackId, deletedIndex);
  for (const store of stores) delete store[deletedKey];

  for (let index = deletedIndex + 1; index < segmentCount; index += 1) {
    const oldKey = segmentStateKey(trackName, trackId, index);
    const newKey = segmentStateKey(trackName, trackId, index - 1);
    for (const store of stores) moveEntry(store, oldKey, newKey);
  }
}

export function clearIndexedSegmentState(stores, trackName, trackId, segmentIndex) {
  const key = segmentStateKey(trackName, trackId, segmentIndex);
  for (const store of stores) delete store[key];
}

export function clearSegmentState(stores, trackName, trackId, segment, index = 0) {
  const key = stableSegmentStateKey(trackName, trackId, segment, index);
  for (const store of stores) delete store[key];
}

export function insertIndexedSegmentState(stores, trackName, trackId, insertIndex, segmentCount) {
  for (let index = segmentCount - 1; index >= insertIndex; index -= 1) {
    const oldKey = segmentStateKey(trackName, trackId, index);
    const newKey = segmentStateKey(trackName, trackId, index + 1);
    for (const store of stores) moveEntry(store, oldKey, newKey);
  }
}

export function removeTrackSegmentState(stores, trackName, trackId) {
  const prefix = `${trackName}_${trackId}_`;
  for (const store of stores) {
    for (const key of Object.keys(store)) {
      if (key.startsWith(prefix)) delete store[key];
    }
  }
}

export function moveSegmentState(
  stores,
  trackName,
  sourceTrackId,
  targetTrackId,
  segment,
  index = 0,
) {
  const sourceKey = stableSegmentStateKey(
    trackName,
    sourceTrackId,
    segment,
    index,
  );
  const targetKey = stableSegmentStateKey(
    trackName,
    targetTrackId,
    segment,
    index,
  );
  for (const store of stores) moveEntry(store, sourceKey, targetKey);
  return { sourceKey, targetKey };
}

export function migrateIndexedSegmentState(stores, tracks) {
  let migratedEntries = 0;
  let assignedIds = 0;
  for (const track of tracks || []) {
    const trackName = legacyTrackName(track.type);
    for (const [index, segment] of (track.segments || []).entries()) {
      const hadIdentity = segment?.id != null && String(segment.id).trim();
      ensureSegmentIdentity(segment, track, index);
      if (!hadIdentity) assignedIds += 1;
      const oldKey = segmentStateKey(trackName, track.id, index);
      const newKey = stableSegmentStateKey(trackName, track.id, segment, index);
      for (const store of stores) {
        if (!Object.hasOwn(store, oldKey)) continue;
        if (!Object.hasOwn(store, newKey)) store[newKey] = store[oldKey];
        delete store[oldKey];
        migratedEntries += 1;
      }
    }
  }
  return { migratedEntries, assignedIds };
}
