import { createHash } from 'crypto';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { loadConfigs } from './config';
import { AppLatestJSONLatest } from '@deskthing/types';
import { writeFile } from 'fs/promises';
import { getReleaseFilePath } from '../utils/filePaths';
import { validateRepoUrl } from '../utils/validateRepoUrl';

const getLatestReleasesFromGithubURLs = (releaseAssetId: string, potentialUrls: string[]): string => {
    for (const url of potentialUrls) {
        try {

            // Match GitHub repository URLs
            const githubMatch = url.match(/github\.com\/([^\/]+)\/([^\/]+)/)
            if (githubMatch) {
                const [, owner, repo] = githubMatch
                // Clean up repo name (remove .git if present)
                const cleanRepo = repo.replace('.git', '')
                // Construct the latest release asset download URL
                return `https://github.com/${owner}/${cleanRepo}/releases/latest/download/${releaseAssetId}`
            }
        } catch (error) {
            console.error('\x1b[90m%s\x1b[0m', 'Error processing github URL:', error)
        }
    }
    return ''
}
export const generateRelease = async () => {
    console.log('\x1b[33m%s\x1b[0m', 'Reading package.json and manifest.json...');
    const { packageJson, manifestJson } = loadConfigs();

    // Calculate hash of the zip file
    console.log('\x1b[33m%s\x1b[0m', 'Calculating package hash...');
    const packageName = packageJson.name;
    const version = manifestJson.version || packageJson.version;
    const distPath = join(process.cwd(), 'dist');
    const zipPath = join(distPath, `${packageName}-v${version}.zip`);

    const iconPath = join(distPath, 'icons', `${manifestJson.id}.svg`);
    const iconPathAlt = join(distPath, 'images', `${manifestJson.id}.svg`);

    const iconFilePath = existsSync(iconPath) ? iconPath : existsSync(iconPathAlt) ? iconPathAlt : null;
    const icon = iconFilePath ? `data:image/svg+xml;base64,${readFileSync(iconFilePath, 'base64')}` : '';

    if (icon) {
        console.log('\x1b[33m%s\x1b[0m', 'Icon found, adding to release metadata...');
    }

    // Always prefer the provided updateUrl, but fallback to GitHub URLs generating a new one if it's not provided
    const updateUrl = getLatestReleasesFromGithubURLs(
        `${packageName}-v${version}.zip`,
        [
            manifestJson.repository,
            packageJson.repository?.url,
        ]
    );

    let fileHash = '';
    let fileSize: number = -1;
    try {
        const fileBuffer = readFileSync(zipPath);
        const hashSum = createHash('sha512');
        hashSum.update(fileBuffer);
        fileHash = hashSum.digest('hex');
        fileSize = fileBuffer.length;
    } catch (err) {
        console.warn('\x1b[33m%s\x1b[0m', 'Could not generate hash for package file');
    }

    console.log('\x1b[33m%s\x1b[0m', 'Generating release metadata...');

    const isValidUrl = await validateRepoUrl(manifestJson.repository);

    if (isValidUrl) {
        console.log("\x1b[32m%s\x1b[0m", "✅ Url is valid");
    } else {
        console.error("\x1b[31m%s\x1b[0m", `⚠️ Url ${manifestJson.repository} is not valid! You may need to provide a valid GitHub repository URL in manifest.json. If you ignore, DeskThing will be unable to download your app`);
    }

    const release: AppLatestJSONLatest = {
        meta_version: '0.11.8', // latest version of the release
        meta_type: 'app',
        repository: manifestJson.repository || packageJson.repository?.url,
        icon: icon,
        size: fileSize,
        appManifest: manifestJson,
        updateUrl: updateUrl,
        hash: fileHash,
        hashAlgorithm: "sha512",
        updatedAt: Date.now(),
        createdAt: Date.now(),
        downloads: 0,
    }

    return release;
}

export async function createReleaseFile() {
    console.log('\x1b[33m%s\x1b[0m', 'Creating release file...');


    try {
        const release = await generateRelease();

        const releaseFilePath = await getReleaseFilePath(release.appManifest.id);

        await writeFile(releaseFilePath, JSON.stringify(release, null, 2));

        console.log('\x1b[32m%s\x1b[0m', 'Release file created successfully');
    } catch (err) {
        console.error('\x1b[31m%s\x1b[0m', 'Failed to create release file:', err);
    }
}