import { VersionInfo } from '@joplin/lib/services/plugins/api/types';
import { Implementation as WindowImplementation } from '@joplin/lib/services/plugins/api/JoplinWindow';
import Setting from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry';
import BasePlatformImplementation, { Joplin } from '@joplin/lib/services/plugins/BasePlatformImplementation';
import { Implementation as ImagingImplementation } from '@joplin/lib/services/plugins/api/JoplinImaging';
import RNVersionInfo from 'react-native-version-info';
import { _ } from '@joplin/lib/locale';
import shim from '@joplin/lib/shim';
import Clipboard from '@react-native-community/clipboard';



interface Components {
	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
	[key: string]: any;
}

// PlatformImplementation provides access to platform specific dependencies,
// such as the clipboard, message dialog, etc. It allows having the same plugin
// API for all platforms, but with different implementations.
export default class PlatformImplementation extends BasePlatformImplementation {

	private static instance_: PlatformImplementation;
	private joplin_: Joplin;
	private components_: Components;

	public static instance(): PlatformImplementation {
		if (!this.instance_) this.instance_ = new PlatformImplementation();
		return this.instance_;
	}

	public get versionInfo(): VersionInfo {
		return {
			version: RNVersionInfo.appVersion,
			syncVersion: Setting.value('syncVersion'),
			profileVersion: reg.db().version(),
			platform: 'mobile',
		};
	}

	public constructor() {
		super();

		this.components_ = {};

		this.joplin_ = {
			views: {
				dialogs: {
					showMessageBox: async (message: string) => {
						return await shim.showMessageBox(
							message,
							{ title: _('Plugin message') },
						);
					},
					showOpenDialog: async (_options) => {
						throw new Error('Not implemented: showOpenDialog');
					},
				},
			},
		};
	}

	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
	public registerComponent(name: string, component: any) {
		this.components_[name] = component;
	}

	public unregisterComponent(name: string) {
		delete this.components_[name];
	}

	public get joplin(): Joplin {
		return this.joplin_;
	}

	public get imaging(): ImagingImplementation {
		return {
			nativeImage: null,
			getPdfInfo: async () => {
				throw new Error('Not implemented: getPdfInfo');
			},
		};
	}

	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
	public get nativeImage(): any {
		return null;
	}

	public get clipboard() {
		// Deny access to the clipboard on iOS, as per AppStore guidelines
		// (as of March 2024).
		if (shim.mobilePlatform() === 'ios') {
			return {
				readText: () => {
					throw new Error('Not available on iOS');
				},
				writeText: () => {
					throw new Error('Not available on iOS');
				},
				availableFormats: (): string[] => [],
			};
		}
		return {
			readText: () => Clipboard.getString(),
			writeText: (text: string) => Clipboard.setString(text),
			availableFormats: () => ['text/plain'],
		};
	}

	public get window(): WindowImplementation {
		return {
			injectCustomStyles: null,
		};
	}
}
