import { AnchorProvider, Program } from '@coral-xyz/anchor';

import liqsolCoreJson from '../../assets/solana/idl/liqsol_core.json';
import liqsolTokenJson from '../../assets/solana/idl/liqsol_token.json';
import validatorLeaderboardJson from '../../assets/solana/idl/validator_leaderboard.json';

import type { LiqsolCore } from '../../assets/solana/types/liqsol_core';
import type { LiqsolToken } from '../../assets/solana/types/liqsol_token';
import type { ValidatorLeaderboard } from '../../assets/solana/types/validator_leaderboard';

import { PROGRAM_IDS } from './constants';

type Entry<IDL> = {
    idl: IDL & { address: string };
    address: string;
};

const PROGRAMS = {
    liqsolCore: {
        idl: liqsolCoreJson,
        address: PROGRAM_IDS.LIQSOL_CORE.toBase58(),
    } as Entry<LiqsolCore>,
    liqsolToken: {
        idl: liqsolTokenJson,
        address: PROGRAM_IDS.LIQSOL_TOKEN.toBase58(),
    } as Entry<LiqsolToken>,
    validatorLeaderboard: {
        idl: validatorLeaderboardJson,
        address: PROGRAM_IDS.VALIDATOR_LEADERBOARD.toBase58(),
    } as Entry<ValidatorLeaderboard>,
} as const;

export type SolanaProgramName = keyof typeof PROGRAMS;

export class SolanaProgramService {
    constructor(private provider: AnchorProvider) { }

    getProgram<K extends SolanaProgramName>(name: K): Program<(typeof PROGRAMS)[K]['idl']> {
        const { idl, address } = PROGRAMS[name];
        const idlWithAddr = { ...idl, address };
        return new Program(idlWithAddr, this.provider) as Program<(typeof PROGRAMS)[K]['idl']>;
    }

    listProgramNames(): SolanaProgramName[] {
        return Object.keys(PROGRAMS) as SolanaProgramName[];
    }
}