import crypto from 'node:crypto';

import { raw } from 'hono/html';
import { renderToString } from 'hono/jsx/dom/server';

import type { Route } from '@/types';
import { ViewType } from '@/types';
import cache from '@/utils/cache';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';

import { getAppreciatedQuery, getProfileProjectsAndSelectionsQuery, getProjectPageQuery } from './queries';

export const route: Route = {
    path: '/:user/:type?',
    categories: ['design'],
    view: ViewType.Pictures,
    example: '/behance/mishapetrick',
    parameters: {
        user: 'username',
        type: {
            description: 'type',
            options: [
                { value: 'projects', label: 'projects' },
                { value: 'appreciated', label: 'appreciated' },
            ],
            default: 'projects',
        },
    },
    features: {
        requireConfig: false,
        requirePuppeteer: false,
        antiCrawler: false,
        supportBT: false,
        supportPodcast: false,
        supportScihub: false,
    },
    name: 'User Works',
    maintainers: ['MisteryMonster'],
    handler,
    description: `Behance user's profile URL, like [https://www.behance.net/mishapetrick](https://www.behance.net/mishapetrick) the username will be \`mishapetrick\`。`,
};

const getUserProfile = async (nodes, user) =>
    (await cache.tryGet(`behance:profile:${user}`, () => {
        const profile = nodes.flatMap((item) => item.owners).find((owner) => owner.username === user);

        return Promise.resolve({
            displayName: profile.displayName,
            id: profile.id,
            link: profile.url,
            image: profile.images.size_50.url.replace('/user/50/', '/user/source/'),
        });
    })) as { displayName: string; id: string; link: string; image: string };

const renderDescription = (description, modules) =>
    renderToString(
        <>
            {description?.length ? (
                <>
                    {description}
                    <br />
                </>
            ) : null}
            {modules?.map((module) => {
                if (module.__typename === 'ImageModule') {
                    return (
                        <>
                            <figure>
                                <img src={module.imageSizes?.allAvailable?.[0]?.url} alt={module.altText ?? undefined} />
                                {module.caption?.length ? <figcaption>{module.caption}</figcaption> : null}
                            </figure>
                            <br />
                        </>
                    );
                }
                if (module.__typename === 'TextModule') {
                    return (
                        <>
                            {module.text ? raw(module.text) : null}
                            <br />
                        </>
                    );
                }
                if (module.__typename === 'MediaCollectionModule') {
                    return (
                        <>
                            {module.components?.map((comp) => (
                                <img src={`https://mir-s3-cdn-cf.behance.net/project_modules/source/${comp.filename}`} alt="" />
                            ))}
                            <br />
                        </>
                    );
                }
                if (module.__typename === 'EmbedModule') {
                    const embed = module.fluidEmbed || module.originalEmbed;
                    return (
                        <>
                            {embed ? raw(embed) : null}
                            <br />
                        </>
                    );
                }

                return (
                    <>
                        UNHANDLED MODULE: {module.__typename}
                        <br />
                    </>
                );
            })}
        </>
    );

async function handler(ctx) {
    const { user, type = 'projects' } = ctx.req.param();

    const uuid = crypto.randomUUID();
    const headers = {
        Cookie: `gk_suid=${Math.random().toString().slice(2, 10)}, gki=; originalReferrer=; bcp=${uuid}`,
        'X-BCP': uuid,
        'X-Requested-With': 'XMLHttpRequest',
    };

    const response = await ofetch('https://www.behance.net/v3/graphql', {
        method: 'POST',
        headers,
        body: {
            query: type === 'projects' ? getProfileProjectsAndSelectionsQuery : getAppreciatedQuery,
            variables: {
                username: user,
                after: '',
            },
        },
    });

    const nodes = type === 'projects' ? response.data.user.profileProjects.nodes : response.data.user.appreciatedProjects.nodes;
    const list = nodes.map((item) => ({
        title: item.name,
        link: item.url,
        author: item.owners.map((owner) => owner.displayName).join(', '),
        image: item.covers.size_202.url.replace('/202/', '/source/'),
        pubDate: item.publishedOn ? parseDate(item.publishedOn, 'X') : undefined,
        category: item.fields?.map((field) => field.label.toLowerCase()),
        projectId: item.id,
    }));

    const profile = await getUserProfile(nodes, user);

    const items = await Promise.all(
        list.map((item) =>
            cache.tryGet(item.link, async () => {
                const response = await ofetch('https://www.behance.net/v3/graphql', {
                    method: 'POST',
                    headers,
                    body: {
                        query: getProjectPageQuery,
                        variables: {
                            projectId: item.projectId,
                        },
                    },
                });
                const project = response.data.project;

                item.description = renderDescription(project.description, project.allModules);
                item.category = [...new Set([...(item.category || []), ...(project.tags?.map((tag) => tag.title.toLowerCase()) || [])])];
                item.pubDate = item.pubDate || (project.publishedOn ? parseDate(project.publishedOn, 'X') : undefined);

                return item;
            })
        )
    );

    return {
        title: `${profile.displayName}'s ${type}`,
        link: `https://www.behance.net/${user}/${type}`,
        image: profile.image,
        item: items,
    };
}
