import { AlignedLyric, SimpleAlignedLyric } from '../types';

export const getLyricStartSeconds = (
  lyric: AlignedLyric,
  fallback: number = 0
) => {
  return lyric.timing?.type === 'point'
    ? lyric.timing.seconds
    : lyric.timing?.type === 'range'
      ? lyric.timing?.startSeconds
      : fallback;
};

export const getLyricEndSeconds = (
  lyric: AlignedLyric,
  fallback: number = Infinity
) => {
  return lyric.timing?.type === 'point'
    ? lyric.timing.seconds
    : lyric.timing?.type === 'range'
      ? lyric.timing?.endSeconds
      : fallback;
};

export const moveAlignedLyric = (lyric: AlignedLyric, deltaSeconds: number) => {
  if (lyric.timing?.type === 'point') {
    return {
      ...lyric,
      timing: {
        ...lyric.timing,
        seconds: lyric.timing.seconds + deltaSeconds,
      },
    };
  } else if (lyric.timing?.type === 'range') {
    return {
      ...lyric,
      timing: {
        ...lyric.timing,
        startSeconds: lyric.timing.startSeconds + deltaSeconds,
        endSeconds: lyric.timing.endSeconds + deltaSeconds,
      },
    };
  } else {
    return lyric;
  }
};

export default function refineAlignedLyrics(
  alignedLyrics: SimpleAlignedLyric[],
  previousAlignedLyrics?: SimpleAlignedLyric[]
) {
  const result: AlignedLyric[] = [];
  const splitAlignedLyrics: SimpleAlignedLyric[] = alignedLyrics
    .map((lyric) => {
      if (lyric.text.includes('\n')) {
        const result: SimpleAlignedLyric[] = [];
        lyric.text.split('\n').forEach((line, index) => {
          if (index > 0) {
            result.push({
              text: '\n',
              startSeconds: lyric.startSeconds,
              endSeconds: lyric.endSeconds,
            });
          }
          if (line) {
            result.push({
              text: line,
              startSeconds: lyric.startSeconds,
              endSeconds: lyric.endSeconds,
            });
          }
        });
        return result;
      } else {
        return [lyric];
      }
    })
    .flat();
  splitAlignedLyrics.forEach((simpleAlignedLyric, index) => {
    const next = splitAlignedLyrics[index + 1];
    const prev = splitAlignedLyrics[index - 1];
    const text = simpleAlignedLyric.text;
    const leadingWhitespace = text.match(/^\s*/)?.[0] || '';
    const trailingWhitespace = text.match(/\s*$/)?.[0] || '';
    const trimmedText = text.trim();
    const sectionTags = trimmedText.match(/^\s*\[.*\]\s*/)?.[0] || '';

    if (leadingWhitespace) {
      let finalText = ' ';
      if (leadingWhitespace.includes('\n')) {
        finalText = '\n';
      }

      if (result.length > 0 && result[result.length - 1]?.text !== finalText) {
        result.push({
          text: finalText,
          dirty: false,
          timing: null,
        });
      }
    }

    if (sectionTags) {
      if ((previousAlignedLyrics?.length || 0) + result.length > 0) {
        result.push({
          text: '\n',
          dirty: false,
          timing: null,
        });
      }
      result.push({
        text: sectionTags,
        dirty: false,
        timing:
          simpleAlignedLyric.startSeconds !== simpleAlignedLyric.endSeconds
            ? {
                type: 'point',
                seconds: simpleAlignedLyric.startSeconds,
              }
            : next
              ? {
                  type: 'point',
                  seconds: next.startSeconds,
                }
              : prev
                ? {
                    type: 'point',
                    seconds: prev.endSeconds,
                  }
                : null,
      });
      const afterSectionTags = trimmedText.slice(sectionTags.length).trim();
      if (afterSectionTags.length > 0) {
        result.push({
          text: afterSectionTags,
          dirty: false,
          timing: {
            type: 'range',
            startSeconds: simpleAlignedLyric.startSeconds,
            endSeconds: simpleAlignedLyric.endSeconds,
          },
        });
        result.push({
          text: '\n',
          dirty: false,
          timing: null,
        });
      }
    } else if (trimmedText) {
      const lines = trimmedText.split('\n');
      const nextText = next?.text || '';
      const nextTextSpecialCharMatch = nextText.match(/^[.!?]*[)\]\}>]*/)?.[0];
      lines.forEach((line, index, list) => {
        if (!line.trim()) return;
        if (index > 0) {
          result.push({
            text: '\n',
            dirty: false,
            timing: null,
          });
        }
        if (index === list.length - 1 && nextTextSpecialCharMatch) {
          line += nextTextSpecialCharMatch;
          next!.text = next!.text.slice(nextTextSpecialCharMatch.length);
        }
        result.push({
          text: line,
          dirty: false,
          timing: {
            type: 'range',
            startSeconds: simpleAlignedLyric.startSeconds,
            endSeconds: simpleAlignedLyric.endSeconds,
          },
        });
      });
    }

    if (result.length > 0 && trailingWhitespace) {
      let finalText = ' ';
      if (trailingWhitespace.includes('\n')) {
        finalText = '\n';
      }
      if (result[result.length - 1]?.text !== finalText) {
        result.push({
          text: finalText,
          dirty: false,
          timing: null,
        });
      }
    }
  });

  return result;
}

if (typeof window !== 'undefined') {
  (window as any).refineAlignedLyrics = refineAlignedLyrics;
}
