'use client'

import { useState, useEffect } from 'react'

import NetworkError     from './types/error/network';
import ContentTypeError from './types/error/content_type';
import ImageContent     from './types/image';
import MarkdownContent  from './types/markdown';
import Terminal         from './types/terminal';
import Text             from './types/text';
import { map_to_type }  from './types/text';

type ContentType<T> = {
	content_type: RegExp,
	path?: RegExp,
	emit: () => void | Processor<T>,
};
type Processor<T> = {
	process:     (response: Response) => Promise<T>,
	postprocess: (data: T) => undefined,
};

function not_match(regex: RegExp | undefined, str: string) {
	return !(regex ?? /(?:)/).test(str);
}

function is_type(response: Response, type: ContentType<any>) {
	if (not_match(type.content_type, response.headers.get('Content-Type')!.split(';')[0])) {
		return false;
	} else if (not_match(type.path, window.location.pathname)) {
		return false;
	}
	return true;
}

export default function Content({ src }: { src: string}) {
	const [content, set_content] = useState<JSX.Element>();

	const recognized_types: ContentType<any>[] = [{
		content_type: /image\/\w+/,
		emit: () => {
			set_content(<ImageContent src={src} />);
		},
	}, {
		content_type: /application\/octet-stream/,
		path: /.*\.term/,
		emit: () => {
			return {
				process: (response: Response) => {
					return response.text();
				},
				postprocess: (data: string) => {
					set_content(<Terminal text={data} />);
				}
			};
		}
	}, {
		content_type: /application\/octet-stream/,
		path: /.*\.md/i,
		emit: () => {
			return {
				process: (response: Response) => {
					return response.text();
				},
				postprocess: (data: string) => {
					set_content(<MarkdownContent text={data} />);
				}
			};
		}
	}, {
		content_type: /(text\/\w+)|(application\/octet-stream)/,
		emit: () => {
			return {
				process: (response: Response) => {
					return response.text();
				},
				postprocess: (data: string) => {
					const split = window.location.pathname.split('.');
					set_content(<Text language={split.length == 0 ? 'none' : map_to_type(split[split.length - 1])} text={data} line_numbers={true} />);
				}
			};
		}
	}];

	useEffect(() => {
		if (content == undefined) {
			const result = fetch(src)
				.then(response => {
					for (const type of recognized_types) {
						if (is_type(response, type)) {
							const emitted = type.emit();
							if (emitted != undefined) {
								result.then(emitted.postprocess);
								return emitted.process(response);
							}
							return;
						}
					}
					set_content(<ContentTypeError content_type={response.headers.get('Content-Type')!.split(';')[0]} />);
				})
				.catch(err => {
					set_content(<NetworkError err={err} />);
				});
		}
	});

	return content ?? <p>Loading...</p>;
}
