import { z } from "zod";
import { payloadSchema } from "./schemas";

export abstract class RJSVM<State_T = any, Definitions_T extends Function_Map = Function_Map>{
    owner: string
    state: State_T
    sync_block_height: number
    config: RJSVM_Config
    definitions: RJSVM_Implementations<RJSVM<any, Definitions_T>, Definitions_T>
    connect: () => Promise<void>
    disconnect: () => Promise<void>
    on: (event: string, handler: ParameterizedFunction) => void
    once: (event: string, handler: ParameterizedFunction) => void
}

export type Generic_Ctor_ReturnType<Ctor> 
= Ctor extends new (...args:any) => infer T ? T
: Ctor extends abstract new (...args:any) => infer A ? A
: never

export type State_Of<T extends RJSVM> = T extends RJSVM<infer State_T> ? State_T : any
export type Endpoints_Of<T extends RJSVM> = T extends RJSVM<any, infer Endpoints_T> ? Endpoints_T : any


export type PaymentTx_T = {
    Account: string,
    Amount: string,
    Destination: string,
    Fee: string,
    Flags: number,
    LastLedgerSequence: number,
    Memos: any[],
    Sequence: number,
    SigningPubKey: string,
    TransactionType: 'Payment',
    TxnSignature: string,
    date: number,
    hash: string,
    inLedger: number,
    ledger_index: number
}

export type ParameterizedFunction = (...args: any) => void

export type Function_Map = {
    [K in string]: ParameterizedFunction
}

export type RJSVM_Endpoint<
    RJSVM_T extends RJSVM<any, Definitions_T>,
    Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>,
    Impl extends RJSVM_EndpointHandler<RJSVM_T, Definitions_T, ParameterizedFunction> = RJSVM_EndpointHandler<RJSVM_T, Definitions_T, ParameterizedFunction>
> = {
    implementation: Impl
    visibility: 'owner' | 'public'
    fee?: number,
    parameterSchema: z.Schema
}

export type RJSVM_Implementations<
    RJSVM_T extends RJSVM<any, Definitions>,
    Definitions extends Function_Map = Endpoints_Of<RJSVM_T>,
> = {
        [Key in keyof Definitions]: RJSVM_Endpoint<RJSVM_T, Definitions, RJSVM_EndpointHandler<RJSVM_T, Definitions, Definitions[Key]>>
    }

export type RJSVM_EndpointHandler<
    RJSVM_T extends RJSVM<any, Definitions_T>,
    Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>,
    Fn extends ParameterizedFunction = ParameterizedFunction,
> =
    (this: RJSVM_T & RJSVM_Interface<RJSVM_T, State_Of<RJSVM_T>, Definitions_T>, env: PaymentTx_T, ...args: Parameters<Fn>) => void

export type RJSVM_Interface<
    RJSVM_T extends RJSVM<State_T, Definitions_T>,
    State_T = State_Of<RJSVM_T>,
    Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>,
> = {
    owner: string
    state: State_T
} & {
    [K in keyof Definitions_T]?: RJSVM_EndpointHandler<RJSVM_T, Definitions_T, Definitions_T[K]>
}

export type RJSVM_Config = {
    rippleNode: string,
    listeningAddress: string
}

export type Payload = z.infer<typeof payloadSchema>