import path from 'node:path'
import config from '@aklive2d/config'
import { file, alphaComposite } from '@aklive2d/libs'
import operators, {
    DIST_DIR,
    OPERATOR_SOURCE_FOLDER,
    generateAssetsJson,
} from '../index.ts'
import { getExtractedFolder, getDistFolder } from './utils.ts'
import type { PortraitHub, PortraitJson } from '../types.ts'

export const build = async (namesToBuild: string[]) => {
    const names = !namesToBuild.length ? Object.keys(operators) : namesToBuild
    console.log('Generating assets for', names.length, 'operators')
    for (const name of names) {
        await generateAssets(name)
        copyVoices(name)
    }
    copyLogos()
}

const copyVoices = (name: string) => {
    file.symlinkAll(
        path.join(OPERATOR_SOURCE_FOLDER, name, config.dir_name.voice.main),
        path.join(DIST_DIR, config.dir_name.voice.main, name)
    )
}

const copyLogos = () => {
    file.symlink(
        path.join(OPERATOR_SOURCE_FOLDER, config.module.operator.logos_assets),
        path.join(DIST_DIR, config.module.operator.logos)
    )
}

const generateAssets = async (name: string) => {
    const extractedDir = getExtractedFolder(name)
    const outDir = getDistFolder(name)
    file.rmdir(outDir)
    file.mkdir(outDir)

    const fallback_name = operators[name].fallback_name
    const fallbackFilename = `${fallback_name}.png`
    const alphaCompositeFilename = `${path.parse(fallbackFilename).name}[alpha].png`
    if (file.exists(path.join(extractedDir, alphaCompositeFilename))) {
        const fallbackBuffer = await alphaComposite.process(
            fallbackFilename,
            alphaCompositeFilename,
            extractedDir
        )
        file.writeSync(
            fallbackBuffer,
            path.join(getDistFolder(name), fallbackFilename)
        )
    } else {
        await file.copy(
            path.join(extractedDir, fallbackFilename),
            path.join(getDistFolder(name), fallbackFilename)
        )
    }

    // generate portrait
    const portraitDir = path.join(
        OPERATOR_SOURCE_FOLDER,
        config.module.operator.portraits
    )
    const portraitHubContent = file.readSync(
        path.join(
            portraitDir,
            config.module.operator.MonoBehaviour,
            'portrait_hub.json'
        )
    ) as string
    if (!portraitHubContent) throw new Error('portrait_hub.json not found')
    const portraitHub: PortraitHub = JSON.parse(portraitHubContent)
    const fallback_name_lowerCase = fallback_name.toLowerCase()
    const portraitItem = portraitHub._sprites.find(
        (item) => item.name.toLowerCase() === fallback_name_lowerCase
    )
    if (!portraitItem) throw new Error(`portrait ${fallback_name} not found`)
    const portraitAtlas = portraitItem.atlas
    const portraitJsonText = file.readSync(
        path.join(
            portraitDir,
            config.module.operator.MonoBehaviour,
            `portraits#${portraitAtlas}.json`
        )
    ) as string
    if (!portraitJsonText)
        throw new Error(`portrait ${fallback_name} json not found`)
    const portraitJson: PortraitJson = JSON.parse(portraitJsonText)
    const item = portraitJson._sprites.find(
        (item) => item.name.toLowerCase() === fallback_name_lowerCase
    )
    if (!item) throw new Error(`portrait ${fallback_name} not found`)
    const rect = {
        ...item.rect,
        rotate: item.rotate,
    }
    const protraitFilename = `portraits#${portraitAtlas}.png`
    const portraitBuffer = await alphaComposite.process(
        protraitFilename,
        `${path.parse(protraitFilename).name}a.png`,
        path.join(portraitDir, config.module.operator.Texture2D)
    )
    const croppedBuffer = await alphaComposite.crop(portraitBuffer, rect)
    file.writeSync(
        croppedBuffer,
        path.join(getDistFolder(name), `${fallback_name}_portrait.png`)
    )

    await generateAssetsJson(
        operators[name].filename,
        extractedDir,
        getDistFolder(name),
        {
            isSP: operators[name].isSP,
        }
    )
}
