
const path = require('path')
const { StatusCodes } = require("http-status-codes")
const { createCRMContact,
    sendMessageSocket,
    mustContainProperties,
    journaling,
    findProperty,
    journalingRequest,
    createContact,
    lookupContactByPhone,
    templateValidator } = require('../utils')
const fs = require("fs")
const { URL } = require('url')
const { oauth2 } = require('../utils')
const { exchangeForTokens } = oauth2
const Company = require('../models/Company')
const CRM = require('../models/CRM')
const CustomError = require('../errors')

const contactCreate = async (req, res) => {

    const { companyId, crmFirstName, crmLastName, crmPhone, crmEmail } = req.body

    mustContainProperties(req, ['companyId', 'crmPhone',])

    await createCRMContact(companyId, crmFirstName, crmPhone, crmEmail, crmLastName)

    res.status(StatusCodes.OK).send()

}

const deleteCrm = async (req, res) => {

    const { companyId, crmBaseURL } = req.body

    mustContainProperties(req, ['companyId', 'crmBaseURL',])

    const crm = await CRM.findOne({
        companyId, crmBaseURL: new URL(crmBaseURL.trim()).hostname
    })

    if (crm) await crm.deleteOne()

    res.status(StatusCodes.OK).send()
}

const deleteCompany = async (req, res) => {

    const { companyId } = req.body

    mustContainProperties(req, ['companyId',])

    const company = await Company.findOne({ companyId, })

    if (company) await company.deleteOne()

    res.status(StatusCodes.OK).send()
}

const callJournaling = async (req, res) => {

    const { companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName } = req.body

    mustContainProperties(req, ['companyId', 'operation', 'crmPhone', 'crmAgent',])

    // if (operation == 'inboundAnsweredCall' && !crmCallDuration)
    //     throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`)
    // if (operation == 'outboundAsweredCall' && !crmCallDuration)
    //     throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`)

    await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName)

    res.status(StatusCodes.OK).send()
} 
  
const install = async (req, res) => {

    const { authUrl, companyId } = req.query

    // Store the authUrl in the session
    req.session.authUrl = authUrl

    res.redirect(authUrl)
}

const oauthCallBack = async (req, res) => {

    const { code } = req.query

    // Retrieve the stored authUrl from the session
    const storedAuthUrl = req.session.authUrl

    const parsedUrl = new URL(storedAuthUrl)
    const clientId = parsedUrl.searchParams.get('client_id')

    if (code) {
        let crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId })
        crmOauth = crmOauth.toObject()

        const authCodeProof = {
            grant_type: 'authorization_code',
            client_id: crmOauth.crm.authentication.crmClientId,
            client_secret: crmOauth.crm.authentication.crmClientSecret,
            redirect_uri: process.env.URL_OAUTH_CALLBACK,
            code
        }

        // Exchange the authorization code for an access token and refresh token 
        await exchangeForTokens(crmOauth, authCodeProof)

        const url = `${process.env.URL_OAUTH_FRONTEND_SUCCESS_REDIRECT}?clientId=${encodeURIComponent(clientId)}`

        return res.redirect(url)
        // return res.redirect(process.env.URL_OAUTH_FRONTEND_SUCCESS_REDIRECT)
    }

    res.status(StatusCodes.OK).send()
}

const testTemplate = async (req, res) => {

    const { clientId, companyId } = req.body

    let crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId, testing: true })

    if (!crmOauth)
        return res.status(StatusCodes.OK).send()

    crmOauth = crmOauth.toObject()

    const { crmPhoneTest } = crmOauth.crm.authentication

    await templateValidator(crmPhoneTest, crmOauth.crm, companyId)

    crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId })
    crmOauth.testing = false
    await crmOauth.save()

    res.status(StatusCodes.OK).send()

}

const uploadCrmConfig = async (req, res) => {

    const { companyId, } = req.body

    mustContainProperties(req, ['companyId',])

    if (!req?.file)
        throw new CustomError.BadRequestError(`The crm property file must be provided`)

    const file = req.file

    let newCrm = fs.readFileSync(file.path, "utf8")

    newCrm = JSON.parse(newCrm)

    const index = newCrm.crmRest.findIndex(rest => rest?.createContactRecord)

    const crmBaseURL = new URL(newCrm.crmRest[index].createContactRecord.request.url.trim()).hostname

    let company = await Company.findOne({ companyId })

    if (!company) {
        company = await Company.create({ companyId })
    }

    let crm = await CRM.findOne({ companyId, crmBaseURL })

    if (crm) {
        crm.testing = true
        crm.crm = newCrm
        await crm.save()
    }
    else {
        crm = await CRM.create({
            crmBaseURL,
            companyId: company.companyId,
            company,
            testing: true,
            crm: newCrm
        })
    }

    fs.unlinkSync(file.path)

    const { type, crmClientId, crmClientSecret, crmScopes, crmPhoneTest } = crm.crm.authentication

    if (type == 'oauth2') {

        const { request, body, response } = findProperty(crm.crm.crmRest, 'authorizationEndpoint')

        let { url } = request

        url = url.replace('crmClientId', crmClientId)
            .replace('crmClientSecret', crmClientSecret)
            .replace('crmScopes', crmScopes)
            .replace('crmRedirectURI', process.env.URL_OAUTH_CALLBACK)


        const authUrl = `http://localhost:6001/api/v1/crm/install?authUrl=${encodeURIComponent(url)}&companyId=${encodeURIComponent(companyId)}`
        console.log('--------> authUrl: ', authUrl)

        return res.status(StatusCodes.OK).json({ url: authUrl })

    }
    else {

        await templateValidator(crmPhoneTest, newCrm, companyId)

        crm.testing = false
        await crm.save()
    }

    res.status(StatusCodes.OK).send()
}

module.exports = {
    contactCreate,
    uploadCrmConfig,
    callJournaling,
    oauthCallBack,
    install,
    deleteCrm,
    deleteCompany,
    testTemplate 
}



