import DocumentType from '../nodes/document-type/DocumentType.js';
import * as PropertySymbol from '../PropertySymbol.js';
import type Document from '../nodes/document/Document.js';
import NodeFactory from '../nodes/NodeFactory.js';

/**
 * The DOMImplementation interface represents an object providing methods which are not dependent on any particular document. Such an object is returned by the.
 */
export default class DOMImplementation {
	#document: Document;

	/**
	 * Constructor.
	 *
	 * @param document Document.
	 */
	constructor(document: Document) {
		this.#document = document;
	}

	/**
	 * Creates and returns an XML Document.
	 *
	 * TODO: Not fully implemented.
	 *
	 * @param _namespaceURI Namespace URI.
	 * @param qualifiedName Qualified name.
	 * @param [_docType] Document type.
	 */
	public createDocument(
		_namespaceURI: string | null,
		qualifiedName: string | null,
		_docType?: string | null
	): Document {
		if (arguments.length < 2) {
			throw new this.#document[PropertySymbol.window].TypeError(
				`Failed to execute 'createDocument' on 'DOMImplementation': 2 arguments required, but only ${arguments.length} present.`
			);
		}

		// The spec declares "qualifiedName" as "[LegacyNullToEmptyString] DOMString",
		// so "null" is coerced to an empty string instead of being rejected.
		qualifiedName = qualifiedName === null ? '' : String(qualifiedName);

		switch (qualifiedName.split(':').pop()) {
			case 'svg':
			case 'xml':
				return new this.#document[PropertySymbol.window].XMLDocument();
			default:
				return new this.#document[PropertySymbol.window].HTMLDocument();
		}
	}

	/**
	 * Creates and returns an HTML Document.
	 */
	public createHTMLDocument(): Document {
		return new this.#document[PropertySymbol.window].HTMLDocument();
	}

	/**
	 * Creates and returns an HTML Document.
	 *
	 * @param qualifiedName Qualified name.
	 * @param publicId Public ID.
	 * @param systemId System ID.
	 */
	public createDocumentType(
		qualifiedName: string,
		publicId: string,
		systemId: string
	): DocumentType {
		const documentType = NodeFactory.createNode<DocumentType>(this.#document, DocumentType);

		documentType[PropertySymbol.name] = qualifiedName;
		documentType[PropertySymbol.publicId] = publicId;
		documentType[PropertySymbol.systemId] = systemId;

		return documentType;
	}
}
