(async function(){
    'use strict';

    var Z=[10,3];
    var GAP=200;
    var MAX_PAGE=200;
    var NL=String.fromCharCode(10);

    function sleep(ms){
        return new Promise(function(resolve){
            setTimeout(resolve,ms);
        });
    }

    function log(){
        var args=['[정리]'].concat(Array.prototype.slice.call(arguments));
        console.log.apply(console,args);
    }

    function atLeast(value,limit){
        return Math.max(value,limit)===value;
    }

    function isDigits(value){
        var s=String(value==null?'':value).trim();
        var i;
        var c;

        if(!s){
            return false;
        }

        for(i=0;i<s.length;i++){
            c=s.charCodeAt(i);

            if(c<48 || c>57){
                return false;
            }
        }

        return true;
    }

    function compactText(value){
        var s=String(value==null?'':value);
        var out='';
        var spaced=false;
        var i;
        var c;

        for(i=0;i<s.length;i++){
            c=s.charCodeAt(i);

            if(c===9 || c===10 || c===13 || c===32){
                if(out && !spaced){
                    out+=' ';
                    spaced=true;
                }
            }else{
                out+=s.charAt(i);
                spaced=false;
            }
        }

        return out.trim();
    }

    function cleanPathParts(pathname){
        var raw=String(pathname||'').split('/');
        var out=[];
        var i;

        for(i=0;i<raw.length;i++){
            if(raw[i]){
                out.push(raw[i]);
            }
        }

        return out;
    }

    function idsFromUrl(value,base){
        try{
            var u=new URL(value,base||location.href);
            var parts=cleanPathParts(u.pathname);
            var index=parts.indexOf('board');

            if(index===-1){
                return null;
            }

            var boardId=parts[index+2]||'';
            var postId=parts[index+3]||'';

            if(!isDigits(boardId)){
                return null;
            }

            return {
                boardId:boardId,
                postId:isDigits(postId)?postId:''
            };

        } catch(error){
            return null;
        }
    }

    var currentUrl=new URL(location.href);

    if(currentUrl.searchParams.get('my')!=='opi'){
        alert('내 댓글 목록 페이지에서 실행하세요.');
        return;
    }

    var BOARD_ID=currentUrl.searchParams.get('come_idx')||'';

    if(!isDigits(BOARD_ID)){
        var currentIds=idsFromUrl(location.href,location.href);

        if(currentIds){
            BOARD_ID=currentIds.boardId;
        }
    }

    if(!isDigits(BOARD_ID)){
        var linksForBoard=document.querySelectorAll('a[href]');
        var boardLinkIndex;

        for(boardLinkIndex=0;boardLinkIndex<linksForBoard.length;boardLinkIndex++){
            var boardIds=idsFromUrl(
                linksForBoard[boardLinkIndex].getAttribute('href'),
                location.href
            );

            if(boardIds && boardIds.postId){
                BOARD_ID=boardIds.boardId;
                break;
            }
        }
    }

    var userNode=document.querySelector('#header-userinfo .user-name');
    var USER_NAME=userNode ? compactText(userNode.textContent) : '';

    if(!isDigits(BOARD_ID) || !USER_NAME){
        alert('게시판 번호 또는 로그인 닉네임을 확인할 수 없습니다.');
        return;
    }

    var randomBytes=crypto.getRandomValues(new Uint8Array(16));
    var CHK='';
    var ri;

    for(ri=0;ri<randomBytes.length;ri++){
        CHK+=randomBytes[ri].toString(16).padStart(2,'0');
    }

    var ignored=new Set();
    var deleted=0;
    var protectedCount=0;
    var skipped=0;

    var box=document.createElement('div');

    box.style=
        'position:fixed;right:15px;bottom:15px;z-index:999999;'+
        'background:#111;color:#fff;padding:12px 15px;'+
        'font:13px/1.55 monospace;border-radius:7px;'+
        'max-width:500px;white-space:pre-wrap;';

    document.body.appendChild(box);

    function status(text){
        box.textContent=
            '[댓글 정리]'+
            NL+
            text+
            NL+
            '삭제 '+deleted+
            ' / 보호 '+protectedCount+
            ' / 제외 '+skipped;
    }

    async function request(params){
        var body=new URLSearchParams();
        var key;

        body.append('comeidx',BOARD_ID);
        body.append('sortorder','date');
        body.append('out','json');
        body.append('replynick','');
        body.append('replyidx','0');
        body.append('chkcode',CHK);
        body.append('uploadurl','');
        body.append('imageposition','');
        body.append('videoloading','lazy');

        for(key in params){
            if(Object.prototype.hasOwnProperty.call(params,key)){
                body.append(key,String(params[key]));
            }
        }

        var response=await fetch(
            '/common/board/comment.json.php?dummy='+Date.now(),
            {
                method:'POST',
                credentials:'include',
                headers:{
                    'Accept':'application/json',
                    'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'
                },
                body:body
            }
        );

        if(response.status===403 || response.status===429){
            throw new Error(
                '서버 제한 감지 HTTP '+response.status
            );
        }

        if(!response.ok){
            throw new Error(
                'HTTP '+response.status
            );
        }

        return response.json();
    }

    function addComments(target,data){
        var groups=data.commentlist||[];
        var gi;
        var ci;
        var list;
        var c;
        var id;

        for(gi=0;gi<groups.length;gi++){
            list=groups[gi].list||[];

            for(ci=0;ci<list.length;ci++){
                c=list[ci];
                id='';

                if(c && c.__attr__ && c.__attr__.cmtidx){
                    id=String(c.__attr__.cmtidx);
                }

                if(id){
                    target.set(id,c);
                }
            }
        }
    }

    async function getComments(articleCode){
        var all=new Map();

        var first=await request({
            articlecode:articleCode,
            act:'list'
        });

        var total=Number(first.cmtcount)||0;
        var step=Number(first.pagecount)||100;
        var pages=Math.ceil(total/step);
        var pageIndex;

        addComments(all,first);

        for(pageIndex=1;pageIndex<pages;pageIndex++){
            var next=await request({
                articlecode:articleCode,
                act:'list',
                titles:String(pageIndex*step)
            });

            addComments(all,next);
        }

        return Array.from(all.values());
    }

    async function removeComment(articleCode,id){
        var result=await request({
            articlecode:articleCode,
            act:'del',
            cmtcodes:String(id)
        });

        return Number(result.message)===1;
    }

    async function getList(page){
        var u=new URL(location.href);

        u.searchParams.set('my','opi');
        u.searchParams.set('p',String(page));

        var response=await fetch(
            u.href,
            {
                credentials:'include',
                cache:'no-store'
            }
        );

        if(response.status===403 || response.status===429){
            throw new Error(
                '서버 제한 감지 HTTP '+response.status
            );
        }

        if(!response.ok){
            throw new Error(
                '목록 HTTP '+response.status
            );
        }

        var html=await response.text();

        var d=new DOMParser()
            .parseFromString(
                html,
                'text/html'
            );

        var posts=new Map();

        var links=
            d.querySelectorAll(
                'a.subject-link[href]'
            );

        var linkIndex;

        for(linkIndex=0;linkIndex<links.length;linkIndex++){
            var ids=idsFromUrl(
                links[linkIndex].getAttribute('href'),
                u.href
            );

            if(
                ids &&
                ids.boardId===String(BOARD_ID) &&
                ids.postId
            ){
                posts.set(
                    ids.postId,
                    {
                        id:ids.postId,

                        title:
                            compactText(
                                links[linkIndex].textContent
                            )||ids.postId
                    }
                );
            }
        }

        if(!posts.size){
            var allRows=
                d.querySelectorAll(
                    'tr'
                );

            var rowIndex;

            for(rowIndex=0;rowIndex<allRows.length;rowIndex++){
                var rowLinks=
                    allRows[rowIndex]
                        .querySelectorAll(
                            'a[href]'
                        );

                var rowLinkIndex;

                for(rowLinkIndex=0;rowLinkIndex<rowLinks.length;rowLinkIndex++){
                    var rowIds=idsFromUrl(
                        rowLinks[rowLinkIndex].getAttribute('href'),
                        u.href
                    );

                    if(
                        rowIds &&
                        rowIds.boardId===String(BOARD_ID) &&
                        rowIds.postId
                    ){
                        posts.set(
                            rowIds.postId,
                            {
                                id:rowIds.postId,

                                title:
                                    compactText(
                                        rowLinks[rowLinkIndex].textContent
                                    )||rowIds.postId
                            }
                        );

                        break;
                    }
                }
            }
        }

        return Array.from(posts.values());
    }

    function plainText(html){
        var temp=
            document.createElement(
                'div'
            );

        temp.innerHTML=
            String(html||'');

        return compactText(
            temp.textContent||
            temp.innerText||
            ''
        ).slice(0,80);
    }

    async function processPost(post){
        status(
            '댓글 조회'+
            NL+
            post.title
        );

        var comments=
            await getComments(
                post.id
            );

        var mine=[];
        var ci;

        for(ci=0;ci<comments.length;ci++){
            if(
                compactText(
                    comments[ci].o_name||''
                )===USER_NAME
            ){
                mine.push(
                    comments[ci]
                );
            }
        }

        mine.reverse();

        var changed=0;
        var mi;

        for(mi=0;mi<mine.length;mi++){
            var c=mine[mi];
            var id='';

            if(
                c &&
                c.__attr__ &&
                c.__attr__.cmtidx
            ){
                id=
                    String(
                        c.__attr__.cmtidx
                    );
            }

            if(
                !id ||
                ignored.has(id)
            ){
                continue;
            }

            var recommend=
                Number(
                    c.o_recommend
                );

            var notrecommend=
                Number(
                    c.o_notrecommend
                );

            var dice=0;

            if(c.__attr__){
                dice=
                    Number(
                        c.__attr__.dice
                    )||0;
            }

            if(
                !Number.isFinite(recommend) ||
                !Number.isFinite(notrecommend) ||
                atLeast(recommend,Z[0]) ||
                atLeast(notrecommend,Z[1]) ||
                dice!==0
            ){
                ignored.add(id);
                protectedCount++;
                continue;
            }

            var text=
                plainText(
                    c.o_comment
                );

            status(
                '삭제 중'+
                NL+
                post.title+
                NL+
                text
            );

            try{
                if(
                    await removeComment(
                        post.id,
                        id
                    )
                ){
                    deleted++;
                    changed++;

                    log(
                        '삭제 완료 | '+
                        post.title+
                        ' | '+
                        text
                    );

                }else{
                    ignored.add(id);
                    skipped++;

                    log(
                        '삭제 거부 | '+
                        post.title
                    );
                }

            } catch(error3){

                if(
                    String(
                        error3.message
                    ).indexOf('403')!==-1 ||
                    String(
                        error3.message
                    ).indexOf('429')!==-1
                ){
                    throw error3;
                }

                ignored.add(id);
                skipped++;

                log(
                    '삭제 실패 | '+
                    post.title+
                    ' | '+
                    error3.message
                );
            }

            await sleep(GAP);
        }

        return changed;
    }

    try{
        var page=1;
        var pageSignatures=new Set();

        while(page<=MAX_PAGE){
            status(
                page+
                '페이지 목록 확인'
            );

            var posts=
                await getList(page);

            if(!posts.length){
                log(
                    page+
                    '페이지 없음 → 종료'
                );

                break;
            }

            posts.reverse();

            var ids=[];
            var si;

            for(si=0;si<posts.length;si++){
                ids.push(
                    posts[si].id
                );
            }

            var sig=
                page+
                '|'+
                ids.join(',');

            log(
                page+
                '페이지 | 게시글 '+
                posts.length+
                '개'
            );

            var changed=0;
            var pi;

            for(pi=0;pi<posts.length;pi++){
                status(
                    page+
                    'P '+
                    (pi+1)+
                    '/'+
                    posts.length+
                    NL+
                    posts[pi].title
                );

                try{
                    changed+=
                        await processPost(
                            posts[pi]
                        );

                } catch(error4){

                    if(
                        String(
                            error4.message
                        ).indexOf('403')!==-1 ||
                        String(
                            error4.message
                        ).indexOf('429')!==-1
                    ){
                        throw error4;
                    }

                    skipped++;

                    log(
                        '게시글 실패 | '+
                        posts[pi].title+
                        ' | '+
                        error4.message
                    );
                }
            }

            if(changed!==0){
                log(
                    page+
                    '페이지 '+
                    changed+
                    '개 삭제 → 재확인'
                );

                continue;
            }

            if(
                pageSignatures.has(sig)
            ){
                log(
                    page+
                    '페이지 변화 없음'
                );
            }

            pageSignatures.add(sig);

            log(
                page+
                '페이지 삭제 가능 댓글 없음 → '+
                (page+1)+
                '페이지'
            );

            page++;
        }

        status('전체 완료');

        log(
            '===== 전체 완료 ====='
        );

        log(
            '삭제 '+deleted
        );

        log(
            '보호 '+protectedCount
        );

        log(
            '삭제 불가/실패 '+
            skipped
        );

    } catch(error5){

        status(
            '중단'+
            NL+
            error5.message
        );

        log(
            '===== 자동 중단 ===== | '+
            error5.message
        );
    }
})();