/**
 * @author Timur Kuzhagaliyev <tim.kuzh@gmail.com>
 * @copyright 2019
 * @license MIT
 */

import { createContext, ElementType, useMemo } from 'react';

import ExactTrie from 'exact-trie';
import { Nullable } from 'tsdef';

import { ChonkyIconPlaceholder } from '../components/internal/ChonkyIconPlaceholder';
import { FileData } from '../types/file.types';
import { ChonkyIconName, ChonkyIconProps, FileIconData } from '../types/icons.types';

export const ChonkyIconContext = createContext<ElementType<ChonkyIconProps>>(ChonkyIconPlaceholder);

export const VideoExtensions: string[] = [
    '3g2',
    '3gp',
    '3gpp',
    'asf',
    'asx',
    'avi',
    'dvb',
    'f4v',
    'fli',
    'flv',
    'fvt',
    'h261',
    'h263',
    'h264',
    'jpgm',
    'jpgv',
    'jpm',
    'm1v',
    'm2v',
    'm4u',
    'm4v',
    'mj2',
    'mjp2',
    'mk3d',
    'mks',
    'mkv',
    'mng',
    'mov',
    'movie',
    'mp4',
    'mp4v',
    'mpe',
    'mpeg',
    'mpg',
    'mpg4',
    'mxu',
    'ogv',
    'pyv',
    'qt',
    'smv',
    'ts',
    'uvh',
    'uvm',
    'uvp',
    'uvs',
    'uvu',
    'uvv',
    'uvvh',
    'uvvm',
    'uvvp',
    'uvvs',
    'uvvu',
    'uvvv',
    'viv',
    'vob',
    'webm',
    'wm',
    'wmv',
    'wmx',
    'wvx',
];
export const ImageExtensions: string[] = [
    '3ds',
    'apng',
    'azv',
    'bmp',
    'bmp',
    'btif',
    'cgm',
    'cmx',
    'djv',
    'djvu',
    'drle',
    'dwg',
    'dxf',
    'emf',
    'exr',
    'fbs',
    'fh',
    'fh4',
    'fh5',
    'fh7',
    'fhc',
    'fits',
    'fpx',
    'fst',
    'g3',
    'gif',
    'heic',
    'heics',
    'heif',
    'heifs',
    'ico',
    'ico',
    'ief',
    'jls',
    'jng',
    'jp2',
    'jpe',
    'jpeg',
    'jpf',
    'jpg',
    'jpg2',
    'jpm',
    'jpx',
    'jxr',
    'ktx',
    'mdi',
    'mmr',
    'npx',
    'pbm',
    'pct',
    'pcx',
    'pcx',
    'pgm',
    'pic',
    'png',
    'pnm',
    'ppm',
    'psd',
    'pti',
    'ras',
    'rgb',
    'rlc',
    'sgi',
    'sid',
    'sub',
    'svg',
    'svgz',
    't38',
    'tap',
    'tfx',
    'tga',
    'tif',
    'tiff',
    'uvg',
    'uvi',
    'uvvg',
    'uvvi',
    'vtf',
    'wbmp',
    'wdp',
    'webp',
    'wmf',
    'xbm',
    'xif',
    'xpm',
    'xwd',
];
export const AudioExtensions: string[] = [
    '3gpp',
    'aac',
    'adp',
    'aif',
    'aifc',
    'aiff',
    'au',
    'caf',
    'dra',
    'dts',
    'dtshd',
    'ecelp4800',
    'ecelp7470',
    'ecelp9600',
    'eol',
    'flac',
    'kar',
    'lvp',
    'm2a',
    'm3a',
    'm3u',
    'm4a',
    'm4a',
    'mid',
    'midi',
    'mka',
    'mp2',
    'mp2a',
    'mp3',
    'mp3',
    'mp4a',
    'mpga',
    'oga',
    'ogg',
    'pya',
    'ra',
    'ra',
    'ram',
    'rip',
    'rmi',
    'rmp',
    's3m',
    'sil',
    'snd',
    'spx',
    'uva',
    'uvva',
    'wav',
    'wav',
    'wav',
    'wax',
    'weba',
    'wma',
    'xm',
];
export const ColorsLight: string[] = [
    '#bbbbbb',
    '#d65c5c',
    '#d6665c',
    '#d6705c',
    '#d67a5c',
    '#d6855c',
    '#d68f5c',
    '#d6995c',
    '#d6a35c',
    '#d6ad5c',
    '#d6b85c',
    '#d6c25c',
    '#d6cc5c',
    '#d6d65c',
    '#ccd65c',
    '#c2d65c',
    '#b8d65c',
    '#add65c',
    '#a3d65c',
    '#99d65c',
    '#8fd65c',
    '#85d65c',
    '#7ad65c',
    '#70d65c',
    '#66d65c',
    '#5cd65c',
    '#5cd666',
    '#5cd670',
    '#5cd67a',
    '#5cd685',
    '#5cd68f',
    '#5cd699',
    '#5cd6a3',
    '#5cd6ad',
    '#5cd6b8',
    '#5cd6c2',
    '#5cd6cc',
    '#5cd6d6',
    '#5cccd6',
    '#5cc2d6',
    '#5cb8d6',
    '#5cadd6',
    '#5ca3d6',
    '#5c99d6',
    '#5c8fd6',
    '#5c85d6',
    '#5c7ad6',
    '#5c70d6',
    '#5c66d6',
    '#5c5cd6',
    '#665cd6',
    '#705cd6',
    '#7a5cd6',
    '#855cd6',
    '#8f5cd6',
    '#995cd6',
    '#a35cd6',
    '#ad5cd6',
    '#b85cd6',
    '#c25cd6',
    '#cc5cd6',
    '#d65cd6',
    '#d65ccc',
    '#d65cc2',
    '#d65cb8',
    '#d65cad',
    '#d65ca3',
    '#d65c99',
    '#d65c8f',
    '#d65c85',
    '#d65c7a',
    '#d65c70',
    '#d65c66',
];
export const ColorsDark: string[] = [
    '#777',
    '#8f3d3d',
    '#8f443d',
    '#8f4b3d',
    '#8f523d',
    '#8f583d',
    '#8f5f3d',
    '#8f663d',
    '#8f6d3d',
    '#8f743d',
    '#8f7a3d',
    '#8f813d',
    '#8f883d',
    '#8f8f3d',
    '#888f3d',
    '#818f3d',
    '#7a8f3d',
    '#748f3d',
    '#6d8f3d',
    '#668f3d',
    '#5f8f3d',
    '#588f3d',
    '#528f3d',
    '#4b8f3d',
    '#448f3d',
    '#3d8f3d',
    '#3d8f44',
    '#3d8f4b',
    '#3d8f52',
    '#3d8f58',
    '#3d8f5f',
    '#3d8f66',
    '#3d8f6d',
    '#3d8f74',
    '#3d8f7a',
    '#3d8f81',
    '#3d8f88',
    '#3d8f8f',
    '#3d888f',
    '#3d818f',
    '#3d7a8f',
    '#3d748f',
    '#3d6d8f',
    '#3d668f',
    '#3d5f8f',
    '#3d588f',
    '#3d528f',
    '#3d4b8f',
    '#3d448f',
    '#3d3d8f',
    '#443d8f',
    '#4b3d8f',
    '#523d8f',
    '#583d8f',
    '#5f3d8f',
    '#663d8f',
    '#6d3d8f',
    '#743d8f',
    '#7a3d8f',
    '#813d8f',
    '#883d8f',
    '#8f3d8f',
    '#8f3d88',
    '#8f3d81',
    '#8f3d7a',
    '#8f3d74',
    '#8f3d6d',
    '#8f3d66',
    '#8f3d5f',
    '#8f3d58',
    '#8f3d52',
    '#8f3d4b',
    '#8f3d44',
];

const getIconTrie = () => {
    let colourIndex = 0;
    const step = 5;

    const IconsToExtensions = [
        // Generic file types
        [ChonkyIconName.license, ['license']],
        [ChonkyIconName.config, ['sfk', 'ini', 'yml', 'toml', 'iml']],
        [ChonkyIconName.model, ['3ds', 'obj', 'ply', 'fbx']],
        [ChonkyIconName.database, ['csv', 'json', 'sql', 'sqlite', 'sqlite3', 'npy', 'npz', 'rec', 'idx', 'hdf5']],
        [ChonkyIconName.text, ['txt', 'md', 'mdx']],
        [ChonkyIconName.archive, ['zip', 'rar', 'tar', 'tar.gz', '7z']],
        [ChonkyIconName.image, ImageExtensions],
        [ChonkyIconName.video, VideoExtensions],
        [ChonkyIconName.code, ['html', 'php', 'css', 'sass', 'scss', 'less', 'cpp', 'h', 'hpp', 'c', 'xml']],
        [ChonkyIconName.info, ['bib', 'readme', 'nfo']],
        [ChonkyIconName.key, ['pem', 'pub']],
        [ChonkyIconName.lock, ['lock', 'lock.json', 'shrinkwrap.json']],
        [ChonkyIconName.music, AudioExtensions],
        [ChonkyIconName.terminal, ['run', 'sh']],
        [ChonkyIconName.trash, ['.Trashes']],
        [ChonkyIconName.users, ['authors', 'contributors']],

        // OS file types
        [ChonkyIconName.linux, ['AppImage']],
        [ChonkyIconName.ubuntu, ['deb']],
        [ChonkyIconName.windows, ['exe']],

        // Programming language file types
        [ChonkyIconName.rust, ['rs', 'rlib']],
        [ChonkyIconName.python, ['py', 'ipynb']],
        [ChonkyIconName.nodejs, ['js', 'jsx', 'ts', 'tsx', 'd.ts']],
        [ChonkyIconName.php, ['php']],

        // Development tools file types
        [ChonkyIconName.git, ['.gitignore']],

        // Brands file types
        [ChonkyIconName.adobe, ['psd']],

        // Other program file types
        [ChonkyIconName.pdf, ['pdf']],
        [ChonkyIconName.excel, ['xls', 'xlsx']],
        [ChonkyIconName.word, ['doc', 'docx', 'odt']],
        [ChonkyIconName.flash, ['swf']],
    ] as const;

    const exactTrie = new ExactTrie({ ignoreCase: true });
    for (const pair of IconsToExtensions) {
        const [icon, extensions] = pair;

        for (let i = 0; i < extensions.length; ++i) {
            colourIndex += step;
            const colorCode = (colourIndex % (ColorsLight.length - 1)) + 1;
            const iconData: FileIconData = {
                icon,
                colorCode,
            };
            exactTrie.put(extensions[i], iconData, true);
        }
    }

    return exactTrie;
};

const iconTrie = getIconTrie();

export const useIconData = (file: Nullable<FileData>): FileIconData => {
    return useMemo(() => {
        if (!file) return { icon: ChonkyIconName.loading, colorCode: 0 };
        if (file.isDir === true) return { icon: ChonkyIconName.folder, colorCode: 0 };

        const match = iconTrie.getWithCheckpoints(file.name, '.', true);
        return match ? match : { icon: ChonkyIconName.file, colorCode: 32 };
    }, [file]);
};
