import { writeFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';

import { parseFetchurl, replaceInFile } from './lib';


/* Constants */
const FLAKE = process.env.FLAKE;

const genVueText = (
    version: string,
    hash: string,
    url: string,
) => `# This file was autogenerated. DO NOT EDIT!
{
  version = "${version}";
  url = "${url}";
  hash = "${hash}";
}
`;

export const updateVuetorrent = () => {
    const FILE = `${FLAKE}/configurations/nos/modules/qbittorrent/vuetorrent.nix`;

    const OLD_VERSION = JSON.parse(spawnSync('nix',
        ['eval', '-f', FILE, '--json'],
        { shell: true }).stdout.toString()).version;

    const VERSION = JSON.parse(spawnSync('curl',
        ['-s', 'https://api.github.com/repos/VueTorrent/VueTorrent/releases/latest'],
        { shell: true }).stdout.toString()).tag_name.replace('v', '');

    const URL = `https://github.com/VueTorrent/VueTorrent/releases/download/v${VERSION}/vuetorrent.zip`;
    const HASH = parseFetchurl(URL);

    const fileText = genVueText(VERSION, HASH, URL);

    writeFileSync(FILE, fileText);

    return OLD_VERSION !== VERSION ? `Vuetorrent: ${OLD_VERSION} -> ${VERSION}` : '';
};


export const updateCustomPackage = (pkg: string) => spawnSync(
    `nix run ${FLAKE}#${pkg}.update`,
    [],
    { shell: true },
).stderr.toString();


const getAttrVersion = (attr: string): string => spawnSync('nix',
    ['eval', '--raw', `${FLAKE}#${attr}.version`],
    { shell: true }).stdout.toString();

export const runNixUpdate = (
    attr: string,
    options: string[] = [],
): { stdout: string, stderr: string } => {
    const OLD_VERSION = getAttrVersion(attr);

    const execution = spawnSync(
        `nix-update --flake ${attr} --write-commit-message >(head -n 1 -) > /dev/null`,
        options,
        { shell: true, cwd: FLAKE },
    );

    const NEW_VERSION = getAttrVersion(attr);

    return {
        stdout: OLD_VERSION !== NEW_VERSION ? execution.stdout.toString() : '',
        stderr: execution.stderr.toString(),
    };
};


const genPluginsText = (
    plugins: Record<string, { url: string, version: string }>,
) => `# This file was autogenerated. DO NOT EDIT!
{
  plugins = {
${Object.entries(plugins)
    .map(([key, value]) => `
    ${key} = {
      url = "${value.url}";
      version = "${value.version}";
    };
    `)
    .join('')}
  };

  hash = "";
}
`;

export const updateCaddyPlugins = () => {
    let updates = '';
    const dir = `${FLAKE}/configurations/cluster/modules/caddy`;

    // Setup workspace
    spawnSync(
        [
            'rm -rf /tmp/update-caddy',
            'mkdir -p /tmp/update-caddy',
            'cd /tmp/update-caddy || exit 1',
            'go mod init temp',
        ].join('; '),
        [],
        { shell: true, cwd: '/tmp' },
    );

    const plugins = JSON.parse(spawnSync('nix',
        ['eval', '-f', `${dir}/plugins.nix`, '--json'],
        { shell: true }).stdout.toString()).plugins as Record<string, { url: string, version: string }>;

    // Get most recent versions of plugins
    Object.entries(plugins).forEach(([key, value]) => {
        const NEW_VERSION = spawnSync([
            'go mod init temp > /dev/null',
            `go get ${value.url} > /dev/null`,
            `grep '${value.url}' go.mod`,
        ].join('; '), [], { shell: true, cwd: '/tmp/update-caddy' })
            .stdout
            .toString()
            .trim()
            .replace(' // indirect', '')
            .split(' ')[1];

        if (plugins[key].version !== NEW_VERSION) {
            updates += `${key}: ${plugins[key].version} -> ${NEW_VERSION}`;
            plugins[key].version = NEW_VERSION;
        }
    });

    writeFileSync(`${dir}/plugins.nix`, genPluginsText(plugins));

    // Get new hash
    const caddyPkgAttr = 'nixosConfigurations.thingone.config.services.caddy.package';

    const NEW_HASH = spawnSync(
        `nix build "$FLAKE#${caddyPkgAttr}" |& sed -n 's/.*got: *//p'`,
        [],
        { shell: true },
    ).stdout.toString().trim();

    replaceInFile(/hash = ".*";/, `hash = "${NEW_HASH}";`, `${dir}/plugins.nix`);

    return updates;
};