import { RPCInterface } from "rpclibrary";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { TableDefiniton, Character } from "../../Types/Types";
import { CharacterManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { FrontworkAdmin } from "../../Admin/Admin";
import { LoginManager } from "./LoginManager";
import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
import { IAdmin } from "../../Admin/Interface";

@Module()
export class CharacterManager
implements FrontworkComponent<CharacterManagerIfc, RPCInterface>{
    name = "CharacterManager" as "CharacterManager";   
    
    @Inject(IAdmin)
    private admin: IAdmin   

    private loginManager : LoginManager

    exportRPCs = () => [
        {
           name: 'getSpecId' as 'getSpecId',
           call: this.getSpecId
        }
    ]

    exportRPCFeatures = () => [
        {
            name: "createCharacter",
            exportRPCs: () => [
                {
                    name: 'createCharacter',
                    call: this.createCharacter
                }
            ]
        }
    ]
    
    getTableDefinitions = (): TableDefiniton[] => [
        {
            name: 'characters',
            tableBuilder: (table) => {
                table.increments("id").primary()
                table.string("name").notNullable().unique()
                table.integer("specid").notNullable()
                table.foreign("specid").references("specs.id")
                table.integer("userid").notNullable()
                table.foreign("userid").references("users.id")
            }
        },{
            name: 'specs',
            tableBuilder: (table) => {
                table.increments("id")
                table.string('class')
                table.string('name')
                table.unique(['class', 'name'])
            }
        }
    ]

    private initialized = false
    initialize = async () => {

        if(!this.initialized)
            this.initialized = true
        //initialize spec table
        await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
    }

    createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
        try{

            await this.admin.knex('characters').insert(character)
            const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
            return char
        }catch(e){
            console.log(e);
            
        }
        throw new Error('Unable to create character')
    }

    getCharacters = async() : Promise<Character[]> => {
        return this.admin.knex.select('*').from('characters')
    }

    getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
    .from('specs')
    .select('id')
    .where({
        class: clazz,
        name: name
    }).first().then(spec => spec.id)

}