/*
 * SPDX-FileCopyrightText: syuilo and misskey-project
 * SPDX-License-Identifier: AGPL-3.0-only
 */

import * as Misskey from 'misskey-js';
import { query } from './url.js';

export class MediaProxy {
	private serverMetadata: Misskey.entities.MetaDetailed;
	private url: string;

	constructor(serverMetadata: Misskey.entities.MetaDetailed, url: string) {
		this.serverMetadata = serverMetadata;
		this.url = url;
	}

	/**
	 * Fetch proxied image URL
	 */
	public getProxiedImageUrl(imageUrl: string, type?: 'preview' | 'emoji' | 'avatar', mustOrigin = false, noFallback = false): string {
		const localProxy = `${this.url}/proxy`;
		let _imageUrl = imageUrl;

		try {
			// Handle already proxied URLs
			if (imageUrl.startsWith(this.serverMetadata.mediaProxy + '/') || imageUrl.startsWith('/proxy/') || imageUrl.startsWith(localProxy + '/')) {
				const extractedUrl = new URL(imageUrl).searchParams.get('url');
				_imageUrl = extractedUrl ?? imageUrl;
			}

			// Validate the URL before returning it
			this.validateUrl(_imageUrl);
		} catch (error) {
			console.error(`Error processing proxied image URL: ${imageUrl}`, error);
			return `${this.serverMetadata.mediaProxy}/fallback.webp`;
		}

		return `${mustOrigin ? localProxy : this.serverMetadata.mediaProxy}/${
			type === 'preview' ? 'preview.webp'
			: 'image.webp'
		}?${query({
			url: _imageUrl,
			...(!noFallback ? { 'fallback': '1' } : {}),
			...(type ? { [type]: '1' } : {}),
			...(mustOrigin ? { origin: '1' } : {}),
		})}`;
	}

	/**
	 * Fetch proxied image URL or return null
	 */
	public getProxiedImageUrlNullable(imageUrl: string | null | undefined, type?: 'preview'): string | null {
		if (imageUrl == null) return null;
		return this.getProxiedImageUrl(imageUrl, type);
	}

	/**
	 * Fetch static image URL
	 */
	public getStaticImageUrl(baseUrl: string): string {
		const u = baseUrl.startsWith('http') ? new URL(baseUrl) : new URL(baseUrl, this.url);

		try {
			// Handle already static or proxied URLs
			if (u.href.startsWith(`${this.url}/emoji/`) || u.href.startsWith(this.serverMetadata.mediaProxy + '/')) {
				u.searchParams.set('static', '1');
				return u.href;
			}

			// Validate the base URL before constructing the static URL
			this.validateUrl(u.href);
		} catch (error) {
			console.error(`Error processing static image URL: ${baseUrl}`, error);
			return `${this.serverMetadata.mediaProxy}/fallback-static.webp`;
		}

		return `${this.serverMetadata.mediaProxy}/static.webp?${query({
			url: u.href,
			static: '1',
		})}`;
	}

	/**
	 * Validate URL format
	 */
	private validateUrl(url: string): void {
		try {
			const parsedUrl = new URL(url);
			if (!parsedUrl.protocol.startsWith('http')) {
				throw new Error(`Invalid URL protocol: ${parsedUrl.protocol}`);
			}
		} catch (error) {
			throw new Error(`Invalid URL: ${url}`);
		}
	}
}
