import {ManipulatorInterfaceType} from '../types'
import fs from 'fs-extra'
import path from 'path'
import utils from '../utils'

type UpdateFileOutConfig = {
    path: string //path without name
    name: string //name without ext
    ext?: string //name without ext
    renameTo?: string //new name
    replaceExisting?: boolean //replace if there is exist the same file ? (default false)
}
type UpdateFileInnerConfig = {
    //together params
    lineParams?: {
        line: number //row number for replace string
        space: number //space number for replace string (from 0)
        len: number //length for replace string to "stringTo" params (iclude first char)
    }
    stringFrom?: string | RegExp //replace match string = string / regexp to find
    stringTo?: string
}
type UpdateFolderOutConfig = {
    path: string //path without name
    name: string //current name without ext (before rename)
    renameTo: string //new name
    replaceExisting?: boolean //replace if there is exist the same file ? (default false)
}

class Updater implements ManipulatorInterfaceType {
    /**
     * update file method actions
     * 1) check exist
     * 2) rename if need
     * 3) read and edit inside content
     * 4) rewrite
     */
    async file(config: UpdateFileInnerConfig & UpdateFileOutConfig) {
        try {
            //file names
            let startFullName = utils.getNameByConfig(config)
            const endFullName = utils.getNameRenameConfig(config)
            //file pathes
            let startFullPath = path.resolve(config.path, startFullName)
            const endFullPath = path.resolve(config.path, endFullName)
            //1) chek exist
            const isExist = await utils.checkExist(startFullPath)
            if (!isExist) return false
            //2) renamed block
            if (!!config?.renameTo) {
                const isRenamed = await utils.rename(startFullPath, endFullPath, !!config?.replaceExisting)
                if (isRenamed) {
                    startFullPath = endFullPath
                } else {
                    return false
                }
            }
            //3) read and edit inside content
            const startContent = await utils.readFile(startFullPath, 'utf8')
            let editedContent = startContent
            const isReplace = config?.stringFrom && config?.stringTo
            if (isReplace) {
                editedContent = editedContent.replace(config.stringFrom || '', config.stringTo || '')
            }
            const isRewrite = !config?.stringFrom && !config?.lineParams && config?.stringTo
            if (isRewrite) {
                editedContent = config.stringTo || ''
            }
            const isEditLines = config?.lineParams && config?.stringTo !== undefined
            if (isEditLines) {
                const {line = 0, len = 0, space = 0} = config?.lineParams || {}
                const arrRows = editedContent.split('\n')
                if (arrRows[line]) {
                    const targetRowCharts = arrRows[line].split('')
                    targetRowCharts.splice(space, len, config.stringTo || '')
                    const editedTargerRowString = targetRowCharts.join('')
                    arrRows[line] = editedTargerRowString
                    const resultFileContent = arrRows.join('\n')
                    editedContent = resultFileContent
                }
            }
            //4) rewrite
            await fs.writeFile(startFullPath, editedContent, {encoding: 'utf8'})
            return true
        } catch (e) {
            console.log(this.constructor.name, `[${this.file.name}]`, config.name, e)
            return false
        }
    }

    /**
     * update folder method actions
     * 1) check exist
     * 2) rename if need
     */
    async folder(config: UpdateFolderOutConfig) {
        try {
            //file names
            const startFullName = `${config.name}`
            const endFullName = config?.renameTo ? `${config?.renameTo}` : startFullName
            //file pathes
            const startFullPath = path.resolve(config.path, startFullName)
            const endFullPath = path.resolve(config.path, endFullName)
            const isExist = await utils.checkExist(startFullPath)
            if (!isExist) return false
            return utils.rename(startFullPath, endFullPath, !!config?.replaceExisting)
        } catch (e) {
            console.log(this.constructor.name, `[${this.folder.name}]`, config.name, e)
            return false
        }
    }
}

export default new Updater()
