// Interfaces
import { Constructor } from "./interfaces/i_Constructor"
import { DeletePayload } from "./interfaces/i_DeletePayload"
import { GetPayload } from "./interfaces/i_GetPayload"
import { PostPayload } from "./interfaces/i_PostPayload"
import { PutPayload } from "./interfaces/i_PutPayload"
import { RequestSettings } from "./interfaces/i_RequestSettings"

// Util Functions
import { combineHeaders, combineSettings } from "./utils/combineFunctions"
import { fetchAction } from "./utils/fetch"

export class R {
    private generalSettingsValue: RequestSettings
    private generalHeadersValue: Headers
    private getSettingsValue: RequestSettings
    private getHeadersValue: Headers
    private postSettingsValue: RequestSettings
    private postHeadersValue: Headers
    private putSettingsValue: RequestSettings
    private putHeadersValue: Headers
    private deleteSettingsValue: RequestSettings
    private deleteHeadersValue: Headers
    private csrfRouteUrlValue: string | undefined

    
    constructor(payload?: Constructor) {
        if(payload){
            // General
            if(payload.generalSettings){
                this.generalSettingsValue = payload.generalSettings
            } else {
                this.generalSettingsValue = {}
            }

            if(payload.generalHeaders){
                if(payload.generalHeaders instanceof Headers){
                    this.generalHeadersValue = payload.generalHeaders
                } else {
                    const headers = new Headers()
                    payload.generalHeaders.forEach(element => {
                        for(const [key, value] of Object.entries(element)){
                            headers.set(key, value)
                        }
                    })
                    this.generalHeadersValue = headers
                }
            } else {
                this.generalHeadersValue = new Headers()
            }

            // Get
            if(payload.getSettings){
                this.getSettingsValue = payload.getSettings
            } else {
                this.getSettingsValue = {}
            }

            if(payload.getHeaders){
                if(payload.getHeaders instanceof Headers){
                    this.getHeadersValue = payload.getHeaders
                } else {
                    const headers = new Headers()
                    payload.getHeaders.forEach(element => {
                        for(const [key, value] of Object.entries(element)){
                            headers.set(key, value)
                        }
                    })
                    this.getHeadersValue = headers
                }
            } else {
                this.getHeadersValue = new Headers()
            }

            // Post 
            if(payload.postSettings){
                this.postSettingsValue = payload.postSettings
            } else {
                this.postSettingsValue = {}
            }

            if(payload.postHeaders){
                if(payload.postHeaders instanceof Headers){
                    this.postHeadersValue = payload.postHeaders
                } else {
                    const headers = new Headers()
                    payload.postHeaders.forEach(element => {
                        for(const [key, value] of Object.entries(element)){
                            headers.set(key, value)
                        }
                    })
                    this.postHeadersValue = headers
                }
            } else {
                this.postHeadersValue = new Headers()
            }

            // Put
            if(payload.putSettings){
                this.putSettingsValue = payload.putSettings
            } else {
                this.putSettingsValue = {}
            }

            if(payload.putHeaders){
                if(payload.putHeaders instanceof Headers){
                    this.putHeadersValue = payload.putHeaders
                } else {
                    const headers = new Headers()
                    payload.putHeaders.forEach(element => {
                        for(const [key, value] of Object.entries(element)){
                            headers.set(key, value)
                        }
                    })
                    this.putHeadersValue = headers
                }
            } else {
                this.putHeadersValue = new Headers()
            }

            // Delete
            if(payload.deleteSettings){
                this.deleteSettingsValue = payload.deleteSettings
            } else {
                this.deleteSettingsValue = {}
            }

            if(payload.deleteHeaders){
                if(payload.deleteHeaders instanceof Headers){
                    this.deleteHeadersValue = payload.deleteHeaders
                } else {
                    const headers = new Headers()
                    payload.deleteHeaders.forEach(element => {
                        for(const [key, value] of Object.entries(element)){
                            headers.set(key, value)
                        }
                    })
                    this.deleteHeadersValue = headers
                }
            } else {
                this.deleteHeadersValue = new Headers()
            }

            // CSRF
            if(payload.csrfUrl){
                this.csrfRouteUrlValue = payload.csrfUrl
            } else {
                this.csrfRouteUrlValue = undefined
            }
        } else {
            this.generalSettingsValue = {}
            this.generalHeadersValue = new Headers()
            this.getSettingsValue = {}
            this.getHeadersValue = new Headers()
            this.postSettingsValue = {}
            this.postHeadersValue = new Headers()
            this.putSettingsValue = {}
            this.putHeadersValue = new Headers()
            this.deleteSettingsValue = {}
            this.deleteHeadersValue = new Headers()
            this.csrfRouteUrlValue = undefined
        }

    }

    async get(payload: GetPayload): Promise<Response> {
        const req = new Request(payload.url, {...combineSettings(this.generalSettingsValue, this.getSettingsValue, payload.settings), headers: combineHeaders(this.generalHeadersValue, this.getHeadersValue, payload.headers),  method: 'GET'})
        return await fetchAction(req, this)
    }

    async getJSON(payload: GetPayload): Promise<Object> {
        return await this.get(payload).then(data => data.json())
    }

    async post(payload: PostPayload): Promise<Response> {
        const req = new Request(payload.url, {...combineSettings(this.generalSettingsValue, this.postSettingsValue, payload.settings), headers: combineHeaders(this.generalHeadersValue, this.postHeadersValue, payload.headers), body: payload.body, method: 'POST'})
        const res =  await fetchAction(req, this)
        console.log(res)
        return res
    }

    async postJSON(payload: PostPayload): Promise<Object> {
        return await this.post(payload).then(data => data.json())
    }

    async put(payload: PutPayload): Promise<Response> {
        const req = new Request(payload.url, {...combineSettings(this.generalSettingsValue, this.putSettingsValue, payload.settings), headers: combineHeaders(this.generalHeadersValue, this.putHeadersValue, payload.headers), body: payload.body, method: 'PUT'})
        return await fetchAction(req, this)
    }

    async putJSON(payload: PutPayload): Promise<Response> {
        return await this.put(payload).then(data => data.json())
    }

    async delete(payload: DeletePayload): Promise<Response> {
        const req = new Request(payload.url, {...combineSettings(this.generalSettingsValue, this.putSettingsValue, payload.settings), headers: combineHeaders(this.generalHeadersValue, this.putHeadersValue, payload.headers), body: payload.body, method: 'DELETE'})
        return await fetchAction(req, this)
    }

    async deleteJSON(payload:DeletePayload): Promise<Response> {
        return await this.delete(payload).then(data => data.json())
    }

    setGeneralHeader(key: string, value: string): void {
        this.generalHeadersValue.set(key, value)
    }

    setGeneralSettings(settings: RequestSettings): void {
        this.generalSettingsValue = {
            ...this.generalSettingsValue,
            ...settings
        }
    }
    
    setGetHeader(key: string, value: string): void {
        this.getHeadersValue.set(key, value)
    }

    setGetSettings(settings: RequestSettings): void {
        this.getSettingsValue = {
            ...this.getSettingsValue,
            ...settings
        }
    }

    setPostHeader(key: string, value: string): void {
        this.postHeadersValue.set(key, value)
    }

    setPostSettings(settings: RequestSettings): void {
        this.postSettingsValue = {
            ...this.postSettingsValue,
            ...settings
        }
    }

    setPutHeader(key: string, value: string): void {
        this.putHeadersValue.set(key, value)
    }

    setPutSettings(settings: RequestSettings): void {
        this.putSettingsValue = {
            ...this.putSettingsValue,
            ...settings
        }
    }
    
    setDeleteHeader(key: string, value: string): void {
        this.deleteHeadersValue.set(key, value)
    }

    setDeleteSettings(settings: RequestSettings): void {
        this.deleteSettingsValue = {
            ...this.deleteSettingsValue,
            ...settings
        }
    }

    get generalHeaders(): Headers {
        return this.generalHeadersValue
    }

    get generalSettings(): RequestSettings {
        return this.generalSettingsValue
    }

    get getHeaders() : Headers {
        return combineHeaders(this.generalHeadersValue, this.getHeadersValue)
    }

    get getSettings(): RequestSettings {
        return combineSettings(this.generalSettingsValue, this.getSettingsValue)
    }

    get postHeaders(): Headers {
        return combineHeaders(this.generalHeadersValue, this.postHeadersValue)
    }

    get postSettings(): RequestSettings {
        return combineSettings(this.generalSettingsValue, this.postSettingsValue)
    }

    get putHeaders(): Headers {
        return combineHeaders(this.generalHeadersValue, this.putHeadersValue)
    }

    get putSettings(): RequestSettings {
        return combineSettings(this.generalSettingsValue, this.putSettingsValue)
    }

    get deleteHeaders(): Headers {
        return combineHeaders(this.generalHeadersValue, this.deleteHeadersValue)
    }

    get deleteSettings(): RequestSettings {
        return combineSettings(this.generalSettingsValue, this.deleteSettingsValue)
    }

    get csrfUrl(): string | undefined {
        return this.csrfRouteUrlValue
    }

    set csrfUrl(url: string) {
        this.csrfRouteUrlValue = url
    }
    
}

