/// @ 0.13.1

### {
    name: 'mish'
    version: '1.3.0.beta'
    author: 'pinky@[email protected]'
    description: 'ノート投稿時に動くコマンドとチェッカーを追加します'
    permissions: ['read:channels']
    config: {
        addfollowFlag: {
            type: 'boolean'
            label: 'フォロー中チャンネルへの投稿コマンドショートカットを追加'
            description: 'ONにすると「!ch 〇〇」の文字列を自動入力するボタンが追加されます'
            default: false
        }
        addfavoriteFlag: {
            type: 'boolean'
            label: 'お気に入りチャンネルへの投稿コマンドショートカットを追加'
            description: 'ONにすると「!ch 〇〇」の文字列を自動入力するボタンが追加されます'
            default: false
        }
        formactWords: {
            type: 'string'
            label: '投稿先チャンネル変更ボタン登録 ※登録すると「!ch 〇〇」の文字列を自動入力するボタンが追加されます'
            description: '複数のチャンネルを指定したい場合、**半角スペース**で区切って指定してください'
            default: ''
        }
        postcheckFlag: {
            type: 'boolean'
            label: '投稿先チェッカー'
            description: 'ON: ノート投稿時に投稿先をダイアログでお知らせ, OFF: ダイアログなし'
            default: true
        }
        postcheckOpt: {
            type: 'boolean'
            label: '投稿先チェッカーオプション※この機能は投稿先チェッカーをONにしたときのみ有効'
            description: 'ON: 常に表示, OFF: 投稿先を変更時のみ表示'
            default: true
        }

        wordcheckFlag: {
            type: 'boolean'
            label: 'ワードチェッカー'
            description: 'ON: ノートに特定ワードが含まれていることをダイアログでお知らせ, OFF: ダイアログなし'
            default: false
        }
        wordcheckOpt: {
            type: 'boolean'
            label: 'ワードチェッカーオプション※この機能はワードチェッカーをONにしたときのみ有効'
            description: 'ON: 常に表示, OFF: パブリック投稿時のみ表示'
            default: false
        }
        ngwords: {
            type: 'string'
            label: 'ワードチェッカーでチェックするNGワードです'
            description: '複数のNGワードを指定したい場合、**半角スペース**で区切って指定してください'
            default: 'ネタバレ ちくちく'
        }
    }
}

let prompt = '!'

// フォロー・お気に入りチャンネル一覧の取得
let channels = {
    all: []
    following: []
    favorited: []
}
channels.following = Mk:api('channels/followed' {limit: 100})
channels.favorited = Mk:api('channels/my-favorites' {limit: 100})
channels.all = channels.following.concat( channels.favorited.filter( @(v, i){ !v.isFollowing } ) )

let persedForm = { cmd: '', args: [], text: '' }
let ngwords = Plugin:config.ngwords.split(' ')
let formactWords = Plugin:config.formactWords.split(' ')

// ドラフト
let drafts = []
@init_drafts() {
    drafts = []
    for (let i, 6) {
        drafts.push({text: '', alias: '', mode: 'ow'})
    }
    Mk:save('MISH_drafts' drafts)
    return true
}

if ( Core:type(Mk:load('MISH_drafts')) == 'null' ) {
    init_drafts()
} else {
    drafts = Mk:load('MISH_drafts')
}

// オブジェクトの中でnullが入っているkeyを削除する関数(ノート投稿時に使用)
@remove_null_property(object) {
    if Core:type(object) != 'obj' {
        return object
    }
    let new_obj = {}
    each let kv Obj:kvs(object) {
        let v = remove_null_property(kv[1])
        if Core:type(v) != 'null' {
            Obj:set(new_obj kv[0] v)
        }
    }
    return new_obj
}

// ノート投稿画面で投稿ボタンではなくプラグインボタンからコマンドを発火させるための関数
@form_exec(form, update) {
    let newText = form.text
    persedForm = cmd_parser(form.text, persedForm)

    match persedForm.cmd {
        // diggy : ノート文の最後に定型文を追加するコマンド
        'diggy' => {
            let diggyword = 'ア アラララア ア アァ!'
            let sep = `{Str:lf}`
            if ( persedForm.text=="" ) { sep = "" } 
            if ( persedForm.args.len > 0 ) {
                match persedForm.args[0] {
                    'w1' => diggyword = '荒 荒 荒波立つ ここは Urbannite ウェカピポ!'
                    'w2' => diggyword = '若 若さの中 不確かな迷いとか ウェカピポ!'
                    'w3' => diggyword = '逆 逆 逆さま World の孤独に強く ウェカピポ!'
                    'fi' => diggyword = 'WA! シュビドゥビドゥバ FEEL ME TONIGHT'
                    'f1' => diggyword = '飛べ 飛ぶなら 飛ぶとき 飛ぼう!'
                    'f2' => diggyword = '飛ぶの? まだ? 飛ぶ 飛びたい'
                    'up' => diggyword = 'あっぷあっぷ UP AND DOWN で HOLD OUT'
                    'h' => diggyword = 'ハァピネス'
                }
            }
            newText = `{persedForm.text}{sep}{diggyword}`
        }
        // clear : 書いている途中のノート内容をクリアするコマンド
        'clear' => {
            newText = ''
        }
        // s: 置換コマンド
        's' => {
            if ( persedForm.args.len >= 2 ) {
                newText = persedForm.text.replace( persedForm.args[0] persedForm.args[1] )
            }
        }
        // save: ドラフト保存コマンド
        'save' => {
            let k = 0
            if ( persedForm.args.len > 0 ) {
                match persedForm.args[0] {
                    '0' => k = 0
                    '1' => k = 1
                    '2' => k = 2
                    '3' => k = 3
                    '4' => k = 4
                    '5' => k = 5
                }
            }
            drafts[k].text = persedForm.text
            if ( persedForm.args.len > 1 ) {
                match persedForm.args[1] {
                    'add' => drafts[k].mode = 'add'
                    * => drafts[k].mode = 'ow'
                }
            }
            Mk:save('MISH_drafts' drafts)
            newText = `{persedForm.text}`
        }
        'load' => {
            let k = 0
            let loadMode = 'ow'
            let loadText = ''
            if ( persedForm.args.len > 0 ) {
                match persedForm.args[0] {
                    '0' => k = 0
                    '1' => k = 1
                    '2' => k = 2
                    '3' => k = 3
                    '4' => k = 4
                    '5' => k = 5
                    'list' => {
                        loadText = '***** Saved Drafts *****'
                        for (let i, 6) {
                            let nolftext = drafts[i].text.replace(`{Str:lf}`, '')
                            loadText = `{loadText}{Str:lf}{i.to_str()}:{drafts[i].mode}: {nolftext.slice(0, 30)}`
                            if (nolftext.len > 30) { loadText = `{loadText} ...` }
                        }
                        loadText = `{loadText}{Str:lf}`
                    }
                }
            }
            if ( persedForm.args.len > 1 ) {
                match persedForm.args[1] {
                    'add' => loadMode = 'add'
                    * => loadMode = 'ow'
                }
            } else {
                loadMode = drafts[k].mode
            }
            if (loadText != '') {
                newText = loadText
            } else if ( loadMode == 'add' ) {
                newText = `{persedForm.text}{Str:lf}{drafts[k].text}`
            } else if ( loadMode == 'ow' ) {
                newText = `{drafts[k].text}`
            }
        }
    }
    update("text", newText)
}

// ノート投稿画面の本文の最後にwordを追加する関数
@form_add(form, update, word) {
    let sep = `{Str:lf}`
    if ( form.text=="" ) { sep = "" } 
    let newText = `{form.text}{sep}{word}`
    update("text", newText)
}

// ノート投稿時にコマンドが発火するようにする関数
@post_exec(note) {
    if ( Core:type(note.text) == 'null' ) { note.text = " " }  // 添付ファイルのみの投稿の場合、note.textがnullになる問題を解消
    // コマンド実行
    let chIsExec = false
    persedForm = cmd_parser(note.text, persedForm)
    match persedForm.cmd {
        'ch' => {
            note.text = persedForm.text
            note = cmd_ch(note, persedForm.args)
            chIsExec = true
        }
    }

    if ( note.text == "" ) { note.text = " " }  // note.textが空文字のとき、remove_null_propertyで削られてしまう問題を解消(添付ファイルのみの投稿対応)

    // 投稿先格納
    let postChname = ""
    if ( Core:type(note.channelId) == 'str' ) {
        each let ch channels.all {
            if ( ch.id == note.channelId ) {
                postChname = ch.name
            }
        }
        if ( postChname == "" ) {
            postChname = Mk:api("channels/show" {channelId: note.channelId}).name
            postChname = `未フォローのチャンネル: {postChname}`
        }
    }
    if (postChname == "") {
        match note.visibility {
            'public' => postChname = "パブリック(ローカルタイムライン)"
            'home' => postChname = "ホーム"
            'followers' => postChname = "フォロワー限定"
            'specified' => postChname = "ダイレクト"
        }
    }

    // 投稿先チェッカー
    let postcheckIsOK = false
    if ( Plugin:config.postcheckFlag && ( Plugin:config.postcheckOpt || chIsExec ) ) {
        postcheckIsOK = Mk:confirm("投稿先の確認" `ノート投稿先は「{postChname}」です。`)
    } else {
        postcheckIsOK = true
    }

    // ワードチェッカー
    let wordcheckIsOK = false
    if ( (Plugin:config.wordcheckFlag && ( Plugin:config.wordcheckOpt || note.visibility == 'public')) && postcheckIsOK ) {
        let existedNgwords = []
        each let word ngwords {
            if ( note.text.incl(word) ) { existedNgwords.push( word ) }
        }
        if ( existedNgwords.len == 0 ) {
            wordcheckIsOK = true
        } else {
            wordcheckIsOK = Mk:confirm("NGワードの確認" `NGワードが含まれます。投稿しますか?{Str:lf}含まれるNGワード:{existedNgwords.join(" ")}`)
        }
    } else {
        wordcheckIsOK = true
    }

    // 投稿先チェックとワードチェックが共にtrueなら投稿
    match ( postcheckIsOK && wordcheckIsOK ) {
        true => { return remove_null_property(note) }
        false => { note.text.value = "" }
    }
}

// コマンドパーサー textにノート投稿画面のformが入ることを想定。返り値はpersedForm = { cmd: "", args: [], text: '' }
@cmd_parser(text, persedForm) {
    let st = text.split(`{Str:lf}`)
    let ll = []
    let cmd = ""
    let args = []
    if ( st.len > 0 ) {
        ll = st[st.len-1].split(" ")
    }
    if ( ll[0].pick(0) == prompt ) {
        cmd = ll[0].slice(1, ll[0].len)
        if ( ll.len > 1 ) {
            ll.shift()
            args = ll
        }
        st.pop()
    }
    persedForm.cmd = cmd
    persedForm.args = args
    persedForm.text = st.join(`{Str:lf}`)
    if ( persedForm.text.pick(persedForm.text.len-1) == `{Str:lf}` ) { persedForm.text.slice(0,persedForm.text.len-1) }
    return persedForm
}

// chコマンド
@cmd_ch(note, args) {
    let matchChs = []
    let matchChsNames = []

    if ( args.len == 0 ) { return note }

    each let ch channels.all {
        let matchFlags = []
        each let word args {
            matchFlags.push( ch.name.incl(word) )
        }
        if ( matchFlags.incl( false ) == false ) {
            matchChs.push(ch)
            matchChsNames.push(ch.name)
        }
    }

    if ( matchChs.len == 1 ) {
        note.channelId = matchChs[0].id
    } else if ( matchChs.len > 1 ) {
        // Mk:dialogを出すとノート投稿処理ができない仕様を使っている 今後のmisskey仕様変更に注意
        Mk:dialog("mish cmd info - ch" `投稿先が複数見つかりました。{Str:lf}{matchChsNames.join(Str:lf)}`)
    } else {
        // Mk:dialogを出すとノート投稿処理ができない仕様を使っている 今後のmisskey仕様変更に注意
        Mk:dialog("mish cmd info - ch" `投稿先が見つかりませんでした。{Str:lf}検索ワード:{args.join(" ")}`)
    }
    return note
}

// saveコマンド
@cmd_save(form, args) {

}

// プラグインボタンの追加
Plugin:register_post_form_action('「!ch 」コマンドを追加', @(form, update) {form_add(form, update, '!ch ')})
if ( Plugin:config.addfollowFlag && Plugin:config.addfavoriteFlag ) {
    each let ch channels.all {
        Plugin:register_post_form_action(`「!ch {ch.name}」コマンドを追加`, @(form, update) {form_add(form, update, `!ch {ch.name}`)})
    }
} else if ( Plugin:config.addfollowFlag && (!Plugin:config.addfavoriteFlag) ) {
    each let ch channels.following {
        Plugin:register_post_form_action(`「!ch {ch.name}」コマンドを追加`, @(form, update) {form_add(form, update, `!ch {ch.name}`)})
    }
} else if ( (!Plugin:config.addfollowFlag) && Plugin:config.addfavoriteFlag ) {
    each let ch channels.favorited {
        Plugin:register_post_form_action(`「!ch {ch.name}」コマンドを追加`, @(form, update) {form_add(form, update, `!ch {ch.name}`)})
    }
}

each let w formactWords {
    if ( w != '' ) {
        Plugin:register_post_form_action(`「!ch {w}」コマンドを追加`, @(form, update) {form_add(form, update, `!ch {w}`)})
    }
}

Plugin:register_post_form_action('mish form_exec', form_exec)
Plugin:register_post_form_action(
    '書いている途中の内容をクリアする',
    @(form, update){
        if (Mk:confirm("Clear" '書いている途中の内容をクリアしますか?')) { update("text", '') }
    }
)

// ノート投稿時にコマンド発火するようにする
Plugin:register_note_post_interruptor(post_exec)