import { Metadata } from 'next';

import { VideoHook } from '@/components/hooksPlayer/useVideoHooks';
import { Clip } from '@/state/clipStore';

import { getClipTitle } from './clip';
import { FALLBACK_IMAGE_URL, FALLBACK_LOGO_URL } from './constants';

export type EmbedUrlOptions = {
  theme?: string;
};

export type EmbedIframeOptions = EmbedUrlOptions & {
  width?: number;
  height?: number;
  autoplay?: boolean | 0 | 1;
};

export type ShareType = 'song' | 'playlist' | 'profile' | 'persona' | 'hook';

const BASE_URL =
  process.env.BASE_URL ||
  (typeof window !== 'undefined' ? window.location.origin : '');

function encodeParams(
  params: Record<string, string | number | boolean | undefined>
) {
  let queryString = '';
  Object.entries(params).forEach(([key, value]) => {
    if (queryString) {
      queryString += '&';
    }
    switch (typeof value) {
      case 'string':
        queryString += `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
        break;
      case 'boolean':
      case 'number':
        queryString += `${encodeURIComponent(key)}=${encodeURIComponent(value.toString())}`;
        break;
      default:
        break;
    }
  });
  return queryString;
}

export function generateUrlWithParams(
  baseUrl: string,
  params?: Record<string, string | number | boolean>
) {
  if (!params) {
    return baseUrl;
  }
  const queryString = encodeParams(params);
  // const searchParams = new URLSearchParams();
  // Object.entries(params).forEach(([key, value]) => {
  //   switch (typeof value) {
  //     case 'string':
  //       searchParams.set(key, value);
  //       break;
  //     case 'boolean':
  //     case 'number':
  //     default:
  //       searchParams.set(key, value.toString());
  //       break;
  //   }
  // });
  // const queryString = searchParams.toString();
  return `${baseUrl}${queryString ? `?${queryString}` : ''}`;
}

const SHARE_TYPE_MAP: Record<
  string,
  | string
  | ((
      params: Record<string, string> & {
        baseUrl: string;
        id: string;
        type: string;
      }
    ) => string)
> = {
  profile: ({ baseUrl, id }) => `${baseUrl}/@${id}`,
  hook: ({ baseUrl, id, handle }) =>
    handle ? `${baseUrl}/@${handle}/hook/${id}` : `${baseUrl}/hook/${id}`,
};

export function generateLinkUrl(
  id: string,
  type: ShareType | 'embed' = 'embed',
  options?: Record<string, string | number | boolean>,
  urlParams?: Record<string, string | undefined>
) {
  const linkUrlType = type in SHARE_TYPE_MAP ? SHARE_TYPE_MAP[type] : type;
  const baseUrl =
    typeof linkUrlType === 'function'
      ? linkUrlType({
          baseUrl: BASE_URL || '',
          id,
          type,
          ...urlParams,
        })
      : `${BASE_URL || ''}/${linkUrlType}/${id}`;
  return generateUrlWithParams(baseUrl, options);
}

export function generateEmbedUrl(
  id: string,
  type: ShareType = 'song', // eslint-disable-line @typescript-eslint/no-unused-vars
  options: EmbedUrlOptions = {}
) {
  return generateLinkUrl(id, 'embed', options);
  // This would be cooler, but we need to change the URL schema
  // ...and actually  add support for playlists and profiles in the iframe
  // const baseUrl = generateLinkUrl(id, type);
  // const searchParams = new URLSearchParams();
  // options.theme && searchParams.set('theme', options.theme);
  // const queryString = searchParams.toString();
  // return `${baseUrl}/embed${queryString ? `?${queryString}` : ''}`;
}

export function generateEmbedCode(
  id: string,
  type: ShareType = 'song',
  options: EmbedIframeOptions = {}
) {
  const { width = 760, height = 240, ...urlOptions } = options;
  const embedUrl = generateEmbedUrl(id, type, urlOptions);
  const fallback = `<a href="${generateLinkUrl(id, type)}">Listen on Suno</a>`;
  return `<iframe src="${embedUrl}" width="${width}" height="${height}">${fallback}</iframe>`;
}

export function extractPlaylistMetadata(playlist: any) {
  const image_url =
    playlist.image_url ||
    playlist.playlist_clips?.[0]?.clip?.image_url ||
    FALLBACK_LOGO_URL;

  const title = `${playlist.name}${!!playlist.user_handle ? ` by @${playlist.user_handle}` : ''} | Suno`;
  const description =
    playlist.description ||
    'Suno is building a future where anyone can make great music.';
  const clip = playlist.playlist_clips?.[0]?.clip;

  return {
    title: title,
    description: description,
    alternates: {
      canonical: generateLinkUrl(playlist.id, 'playlist'),
    },
    openGraph: {
      type: 'music.playlist',
      images: [
        {
          url: image_url!,
          width: 256,
          height: 256,
          type: 'image/png',
        },
      ],
      // audio should be an array of audio_urls
      audio: playlist.playlist_clips
        ?.map((pClip: any) => pClip?.clip?.audio_url)
        .filter((url: string) => !!url),
    },
    twitter: {
      card: 'player',
      title: title,
      description: description,
      site: '@suno_ai_',
      images: [
        {
          url: image_url.replace('image_', 'image_large_'),
        },
        { url: image_url },
      ],
      players: clip
        ? {
            playerUrl: generateLinkUrl(clip?.id, 'embed'),
            streamUrl: clip.audio_url!,
            width: 760,
            height: 240,
          }
        : undefined,
    },
  };
}

export function extractProfileMetadata(profile: any) {
  const image_url = profile.avatar_image_url || FALLBACK_LOGO_URL;

  const title = `${profile.display_name || `@${profile.handle}`} | Join me on Suno`;
  const description =
    profile.profile_description ||
    'Suno is building a future where anyone can make great music.';
  const clip = profile.clips?.[0];

  return {
    metadataBase: new URL('https://cdn1.suno.ai'),
    title: title,
    description: description,
    alternates: {
      canonical: generateLinkUrl(profile.handle, 'profile'),
    },
    openGraph: {
      type: 'music.song',
      images: [
        {
          url: image_url!,
          width: 256,
          height: 256,
          type: 'image/png',
        },
      ],
      audio: [clip?.audio_url],
    },
    twitter: {
      card: 'player',
      title: title,
      description: description,
      site: '@suno_ai_',
      images: [
        {
          url: image_url.replace('image_', 'image_large_'),
        },
        { url: image_url },
      ],
      players: !!clip
        ? {
            playerUrl: generateLinkUrl(clip?.id, 'embed'),
            streamUrl: clip?.audio_url,
            width: 760,
            height: 240,
          }
        : undefined,
    },
  };
}

function getClipTitleWithUsername(
  clip: Clip,
  truncate: boolean,
  includeHandle: boolean
) {
  let clipTitle = getClipTitle(clip);
  if (truncate) {
    clipTitle = clipTitle?.slice(0, 120);
  }

  const title = clipTitle ? `${clipTitle}` : 'Untitled';

  const displayName = clip.display_name;
  const handle = clip.handle;

  if (displayName) {
    if (includeHandle) {
      return `${title} by ${displayName} (@${handle})`;
    } else {
      return `${title} by ${displayName}`;
    }
  } else if (handle) {
    return `${title} by @${handle}`;
  } else {
    return `${title}`;
  }
}

function getPageTitle(clip: Clip) {
  const pageTitle = getClipTitleWithUsername(clip, true, false);
  return `${pageTitle} | Suno`;
}

function getPageDescription(clip: Clip) {
  const pageDescription = getClipTitleWithUsername(clip, false, true);
  return `${pageDescription}. Listen and make your own on Suno.`;
}

export function extractClipMetadata(clip: Clip): Metadata {
  const hasVideo = clip.video_url && clip.status === 'complete';

  const ogVideo = hasVideo
    ? {
        videos: [
          {
            url: clip.video_url!,
            secureUrl: clip.video_url!,
            type: 'video/mp4',
            width: 1280,
            height: 720,
          },
        ],
        // Add explicit video property for better compatibility
        video: [
          {
            url: clip.video_url!,
            secureUrl: clip.video_url!,
            type: 'video/mp4',
            width: 1280,
            height: 720,
          },
        ],
      }
    : null;

  const clipTitleTruncated = getClipTitle(clip)?.slice(0, 160);
  const openGraphTitle = clipTitleTruncated
    ? `${clipTitleTruncated}`
    : 'Untitled';

  const pageTitle = getPageTitle(clip);

  const openGraphDescription = `Listen and make your own on Suno.`;
  const pageDescription = getPageDescription(clip);

  const image_url = clip.image_url || FALLBACK_IMAGE_URL;

  const songUrlForOembed = generateLinkUrl(clip?.id, 'song');

  return {
    metadataBase: new URL('https://cdn1.suno.ai'),

    title: pageTitle,
    description: pageDescription,
    alternates: {
      types: {
        'application/json+oembed': `https://studio-api.prod.suno.com/api/oembed?url=${encodeURIComponent(songUrlForOembed)}`,
      },
      canonical: songUrlForOembed,
    },
    openGraph: {
      // Change the type based on whether video is available
      type: hasVideo ? 'video.other' : 'music.song',
      images: [
        {
          url: image_url,
          width: 256,
          height: 256,
          type: 'image/png',
        },
      ],
      description: openGraphDescription,
      title: openGraphTitle,
      audio: [
        {
          url: clip.audio_url!,
          type: 'audio/mpeg',
        },
      ],
      ...(ogVideo || {}),
    },
    ...(hasVideo
      ? {
          other: {
            medium: 'video',
          },
        }
      : {}),
    twitter: {
      card: 'player',
      title: openGraphTitle,
      description: openGraphDescription,
      site: '@suno_ai_',
      images: [{ url: image_url.replace('image_', 'image_large_') }],
      players: {
        playerUrl: generateLinkUrl(clip?.id, 'embed'),
        streamUrl: clip.audio_url!,
        width: 760,
        height: 240,
      },
    },
  };
}

export function extractPersonaMetadata(persona: any) {
  const image_url = persona.avatar_image_url || FALLBACK_LOGO_URL;

  const title = `${persona.name} | Suno`;
  const description =
    persona.description ||
    'Suno is building a future where anyone can make great music.';
  const clip = persona.persona_clips?.[0]?.clip;

  return {
    metadataBase: new URL('https://cdn1.suno.ai'),
    title: title,
    description: description,
    alternates: {
      canonical: generateLinkUrl(persona.id, 'persona'),
    },
    openGraph: {
      type: 'music.song',
      images: [
        {
          url: image_url!,
          width: 256,
          height: 256,
          type: 'image/png',
        },
      ],
      audio: [clip?.audio_url],
    },
    twitter: {
      card: 'player',
      title: title,
      description: description,
      site: '@suno_ai_',
      images: [
        {
          url: image_url.replace('image_', 'image_large_'),
        },
        { url: image_url },
      ],
      players: !!clip
        ? {
            playerUrl: generateLinkUrl(clip?.id, 'embed'),
            streamUrl: clip?.audio_url,
            width: 760,
            height: 240,
          }
        : undefined,
    },
  };
}

export function extractVideoHookMetadata(hook: VideoHook) {
  const imageUrl = hook.thumbnail_image_url || FALLBACK_LOGO_URL;
  const audioUrl = hook.clip?.audio_url;
  const videoUrl = hook.rendered_video_url;

  const title = `${hook.clip?.title || hook.title || 'Hook'} | Suno`;
  const description =
    hook.caption ||
    'Suno is building a future where anyone can make great music.';

  const metadata = {
    metadataBase: new URL('https://cdn1.suno.ai'),
    title: title,
    description: description,
    alternates: {
      canonical: generateLinkUrl(hook.id, 'hook'),
    },
    openGraph: {
      type: 'video.other',
      images: [
        {
          url: imageUrl,
          width: 256,
          height: 256,
          type: 'image/png',
        },
      ],
    } as NonNullable<Metadata['openGraph']>,
    twitter: {
      card: 'player',
      title: title,
      description: description,
      site: '@suno_ai_',
      images: [
        { url: imageUrl.replace('image_', 'image_large_') },
        { url: imageUrl },
      ],
      // @TODO enable when we have an embed player for hooks
      // players: !!hook
      //   ? {
      //       playerUrl: generateLinkUrl(hook?.id, 'embed'),
      //       streamUrl: hook?.rendered_video_url,
      //       width: 760,
      //       height: 240,
      //     }
      //   : undefined,
    },
  };

  // We should have audio/video URLs to use, but let's make sure
  if (audioUrl) {
    metadata.openGraph.audio = [audioUrl];
  }

  if (videoUrl) {
    metadata.openGraph.videos = [
      {
        url: videoUrl,
        secureUrl: videoUrl,
        type: 'video/mp4',
        // ideally we get these from the hook
        width: 1280,
        height: 720,
      },
    ];
    // @ts-expect-error - Add explicit video property for better compatibility
    metadata.openGraph.video = metadata.openGraph.videos;
  }

  return metadata;
}
