import { parse } from 'partial-json';

import { OptionValue } from './stores';
import { ChatSession } from './types';

export const getModalBaseUrl = () => {
  const env =
    process.env.NEXT_PUBLIC_ORPHEUS_ENV ??
    (process.env.NEXT_PUBLIC_NODE_ENV === 'production' ? 'prod' : 'dev');
  return `https://suno-ai--orpheus-${env}-web.modal.run`;
};

export const parsePartialMessage = (message: object | string) => {
  try {
    const parsed =
      typeof message === 'object' ? message : parse(message || '{}');
    if (parsed?.parsed_content && parsed?.parsedMessage === undefined) {
      parsed.parsedMessage = parsed.parsed_content;
    }
    return parsed;
  } catch (e) {
    return { message };
  }
};

export const getAuraURLForSessionOrProject = (
  sessionOrWorkspaceId: ChatSession | string
) => {
  const auraIndex =
    (parseInt(
      (typeof sessionOrWorkspaceId === 'string'
        ? sessionOrWorkspaceId
        : (sessionOrWorkspaceId.workspace_id ?? sessionOrWorkspaceId.session_id)
      ).split('-')[0],
      16
    ) %
      16) +
    1;
  return `https://cdn1.suno.ai/sAura${auraIndex}.jpg`;
};

export const consolidateMessages = (msgs: any[]) => {
  const toolCallResultMap = new Map<string, any>();
  const consolidatedMessages: any[] = [];
  const currentABMessage: any = {};
  msgs
    .filter((msg) => !!msg.data)
    .forEach((_msg) => {
      const msg = _msg.data;
      if (
        msg.ab_test_group_id &&
        msg.ab_variant &&
        ![true, false].includes(msg.selected_for_ab)
      ) {
        const variant = msg.ab_variant === 'A' ? 'a' : 'b';
        if (!currentABMessage.id) {
          currentABMessage.id = msg.ab_test_group_id;
          currentABMessage.data = { [variant]: [msg] };
        } else if (currentABMessage.id === msg.ab_test_group_id) {
          currentABMessage.data = {
            ...currentABMessage.data,
            [variant]: [...(currentABMessage.data?.[variant] ?? []), msg],
          };
        }
        return;
      } else if (msg.selected_for_ab === false) {
        return;
      }

      const msgClipIds = msg.clipIds || msg.parsed_content?.clipIds;
      if (msgClipIds && msg.tool_call_id) {
        if (toolCallResultMap.has(msg.tool_call_id)) {
          const existing = toolCallResultMap.get(msg.tool_call_id);
          const newClipIds = [...existing.clipIds, ...msgClipIds];
          consolidatedMessages[existing.index] = {
            ...consolidatedMessages[existing.index],
            data: {
              ...consolidatedMessages[existing.index].data,
              clipIds: newClipIds,
            },
          };
          toolCallResultMap.set(msg.tool_call_id, {
            ...existing,
            clipIds: newClipIds,
          });
        } else {
          toolCallResultMap.set(msg.tool_call_id, {
            index: consolidatedMessages.length,
            clipIds: msgClipIds,
          });
          consolidatedMessages.push({ id: _msg.id, data: msg });
        }
      } else {
        consolidatedMessages.push({ id: _msg.id, data: msg });
      }
    });
  if (currentABMessage.id) {
    return [...consolidatedMessages, currentABMessage];
  }
  return consolidatedMessages;
};

export const getUUID = () => {
  const randomUUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
    /[xy]/g,
    (c) => {
      const r = (Math.random() * 16) | 0;
      const v = c === 'x' ? r : (r & 0x3) | 0x8;
      return v.toString(16);
    }
  );
  return randomUUID;
};

export const formatString = (
  template: string,
  values: Record<string, string>
): string => {
  return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
};

/**
 * Extracts the value from an option (which can be a string or an object with value/article_override)
 * and determines the article to use if prefix_with_article is true.
 */
export const getOptionValue = (
  option: OptionValue,
  prefixWithArticle: boolean
): string => {
  const value = typeof option === 'string' ? option : option.value;
  const articleOverride =
    typeof option === 'object' ? option.article_override : undefined;

  if (!prefixWithArticle) {
    return value;
  }

  // Use article_override if provided, otherwise infer from starting vowel
  const article =
    articleOverride ??
    (['a', 'e', 'i', 'o', 'u'].some((vowel) =>
      value.toLowerCase().startsWith(vowel)
    )
      ? 'an'
      : 'a');

  return `${article} ${value}`;
};

const env =
  process.env.NEXT_PUBLIC_ORPHEUS_ENV ??
  (process.env.NEXT_PUBLIC_NODE_ENV === 'production' ? 'prod' : 'dev');

export const MODAL_SRV = `https://suno-ai--orpheus-${env}-web.modal.run`;
