<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
<body>

<section layout:fragment="contentFragment">
    <script>
        require.config({paths: {'vs': '/plugins/vs'}});
    </script>
    <div class="container-fluid mt-2">
        <div class="toast" role="alert" aria-live="assertive" aria-atomic="true" style="position: absolute; top: 0; right: 0;">
            <div class="toast-header">
                <strong class="mr-auto">알림</strong>
                <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
            </div>
            <div class="toast-body">
            </div>
        </div>
        <form name="mockRouteForm" id="mockRouteForm"
              th:action="${mockRoute.id == null}?@{/mgmt/routes/register.do}:@{/mgmt/routes/update.do}"
              th:object='${mockRoute}' method="post">
            <div class="card col-md">
                <div class="card-header">
                    <h3 th:if="${mockRoute.id == null}">API 정보 등록</h3>
                    <h3 th:if="${mockRoute.id != null}">API 정보 수정</h3>
                </div>
                <div class="card-body">
                    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
                    <input type="hidden" name="id" th:value="${mockRoute.id}">
                    <div class="form-floating mt-2">
                        <input type="text" class="form-control"
                               th:classappend="${#fields.hasErrors('name')}? 'is-invalid'" th:field="*{name}" required/>
                        <label for="name" class="form-label must" th:text="#{name}">이름</label>
                        <th:block th:each="err : ${#fields.errors('name')}">
                            <div th:text="${err}" class="invalid-feedback"></div>
                        </th:block>
                    </div>
                    <div class="d-flex align-items-center mt-2">
                        <div class="form-floating col-md-1 me-2">
                            <select name="method" class="form-select" th:if="${mockRoute.id == null}"
                                    th:classappend="${#fields.hasErrors('method')}? 'is-invalid'" id="method">
                                <option th:selected="${mockRoute.method == 'POST'}" value="POST">POST</option>
                                <option th:selected="${mockRoute.method == 'GET'}" value="GET">GET</option>
                                <option th:selected="${mockRoute.method == 'PUT'}" value="PUT">PUT</option>
                                <option th:selected="${mockRoute.method == 'DELETE'}" value="DELETE">DELETE</option>
                                <option th:selected="${mockRoute.method == 'CONNECT'}" value="CONNECT">CONNECT</option>
                                <option th:selected="${mockRoute.method == 'HEAD'}" value="HEAD">HEAD</option>
                                <option th:selected="${mockRoute.method == 'OPTIONS'}" value="OPTIONS">OPTIONS</option>
                                <option th:selected="${mockRoute.method == 'TRACE'}" value="TRACE">TRACE</option>
                                <option th:selected="${mockRoute.method == 'PATCH'}" value="PATCH">PATCH</option>
                            </select>
                            <select name="method" class="form-select" th:if="${mockRoute.id != null}"
                                    th:classappend="${#fields.hasErrors('method')}? 'is-invalid'" id="method">
                                <option th:if="${mockRoute.method == 'POST'}" value="POST">POST</option>
                                <option th:if="${mockRoute.method == 'GET'}" value="GET">GET</option>
                                <option th:if="${mockRoute.method == 'PUT'}" value="PUT">PUT</option>
                                <option th:if="${mockRoute.method == 'DELETE'}" value="DELETE">DELETE</option>
                                <option th:if="${mockRoute.method == 'CONNECT'}" value="CONNECT">CONNECT</option>
                                <option th:if="${mockRoute.method == 'HEAD'}" value="HEAD">HEAD</option>
                                <option th:if="${mockRoute.method == 'OPTIONS'}" value="OPTIONS">OPTIONS</option>
                                <option th:if="${mockRoute.method == 'TRACE'}" value="TRACE">TRACE</option>
                                <option th:if="${mockRoute.method == 'PATCH'}" value="PATCH">PATCH</option>
                            </select>
                            <label for="method" class="form-label must">Method</label>
                        </div>
                        <div class="form-floating col-md">
                            <input type="text" name="pathPattern" class="form-control" id="pathPattern"
                                   th:field="*{pathPattern}" th:readonly="${mockRoute.id != null}"
                                   placeholder="서버에 노출 되는 경로 (/부터 입력)" required>
                            <label for="pathPattern" class="must">Path</label>
                        </div>
                    </div>
                    <div class="form-floating col-md">
                        <input type="hidden" th:classappend="${#fields.hasGlobalErrors() || #fields.hasErrors('pathPattern')}? 'is-invalid'"
                               placeholder="서버에 노출 되는 경로 (/부터 입력)" required th:readonly="${mockRoute.id != null}">
                        <th:block th:each="err : ${#fields.errors('pathPattern')}">
                            <div th:text="${err}" class="invalid-feedback"></div>
                        </th:block>
                    </div>
                    <div id="responses" class="mt-1">
                        <div class="row" th:each="response, status: *{responses}">
                            <input type="number" th:field="*{responses[__${status.index}__].statusCode}" required/>
                            <textarea th:field="*{responses[__${status.index}__].body}"></textarea>
                            <input type="number" th:field="*{responses[__${status.index}__].delay}" required/>
                            <input type="hidden" th:field="*{responses[__${status.index}__].defaultResponse}" />
                            <ul class="response_conditions">
                                <li th:each="condition, status: *{responses[__${status.index}__].conditions}">
                                    <select class="form-select" th:with="matchers1=${@ConditionMatcherService.getMatchersList()}">
                                        <option th:each="item : ${matchers1}" th:value="${item.getType()}" th:text="${item.getDisplayName()}" th:selected="${condition.type == item.getType()}"></option>
                                    </select>
                                    <input type="text" name="key" th:value="${condition.key}"/>
                                    <input type="text" name="value" th:value="${condition.value}"/>
                                </li>
                            </ul>
                            <ul class="response_headers">
                                <li th:each="header, status: *{responses[__${status.index}__].headers}">
                                    <input type="text" name="key" th:value="${header.key}"/>
                                    <input type="text" name="value" th:value="${header.value}"/>
                                </li>
                            </ul>
                        </div>
                    </div>
                    <ul class="nav nav-tabs" id="responseTabTitle" role="tablist">
                    </ul>
                    <div class="tab-content" id="responseTabContent">
                    </div>
                </div>
                <div class="card-footer">
                    <button type="button" class="btn btn-primary btn_list"><i class="fa-solid fa-list"></i> 목록</button>
                    <button type="button" class="btn btn-primary btn_register"><i
                            class="fa-sharp fa-solid fa-floppy-disk"></i> 저장
                    </button>
                </div>
            </div>
        </form>
        <div id="template" style="display: none;">
            <div class="tab-pane" role="tabpanel">
                <div class="row mt-1">
                    <div class="col-md condition">
                        <div class="card">
                            <div class="card-header">
                                <div class="d-flex justify-content-between">
                                    <span>조건 항목</span>
                                    <button type="button" class="btn btn-secondary btn-sm btn_remove_case">제거</button>
                                </div>
                            </div>
                            <div class="card-body">
                                <table class="table">
                                    <thead>
                                    <tr>
                                        <th scope="col">종류</th>
                                        <th scope="col">키</th>
                                        <th scope="col">값</th>
                                        <th>
                                            <button type="button"
                                                    class="btn btn-secondary btn-sm btn_add_condition">추가
                                            </button>
                                        </th>
                                    </tr>
                                    </thead>
                                    <tbody class="response_conditions">
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                    <div class="col-md">
                        <div class="card">
                            <div class="card-header">응답 내용</div>
                            <div class="card-body">
                                <div class="form-floating mt-1">
                                    <input type="hidden" name="defaultResponse" required/>
                                    <input class="form-control" type="number" name="statusCode" required/>
                                    <label class="form-label must">Status</label>
                                </div>
                                <div class="form-floating mt-1">
                                    <input class="form-control" type="number" name="delay" required/>
                                    <label class="form-label must">응답 지연 시간(ms)</label>
                                </div>
                                <label class="form-label mt-1">응답 Body</label>
                                <div class="response_body" style="width:100%;height:250px;border:1px solid grey;"></div>
                                <textarea class="form-control" style="display: none;" name="body"></textarea>
                            </div>
                            <div class="card-body">
                                <table class="table">
                                    <thead>
                                    <tr>
                                        <th scope="col">Header 이름</th>
                                        <th>값</th>
                                        <th>
                                            <button type="button" class="btn btn-secondary btn-sm btn_add_header">
                                                추가
                                            </button>
                                        </th>
                                    </tr>
                                    </thead>
                                    <tbody class="response_headers">
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div id="conditionTemplate" style="display: none;">
            <table>
                <tbody>
                <tr>
                    <td>
                        <select class="form-select" th:with="matchers=${@ConditionMatcherService.getMatchersList()}">
                            <option th:each="item : ${matchers}" th:value="${item.getType()}" th:text="${item.getDisplayName()}"></option>
                        </select>
                    </td>
                    <td>
                        <input class="form-control" type="text" name="key"/>
                    </td>
                    <td>
                        <input class="form-control" type="text" name="value"/>
                    </td>
                    <td>
                        <button type="button" class="btn btn-secondary btn-sm btn_remove_condition">제거</button>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
        <div id="responseHeaderTemplate" style="display: none;">
            <table>
                <tbody>
                <tr>
                    <td>
                        <input class="form-control" type="text" name="key"/>
                    </td>
                    <td>
                        <input class="form-control" type="text" name="value"/>
                    </td>
                    <td>
                        <button type="button" class="btn btn-secondary btn-sm btn_remove_header">제거</button>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>

    </div>
</section>
</body>

<th:block layout:fragment="contentScript">
    <script>
        $(function () {
            let model = {
                name: '',
                method: '',
                pathPattern: '',
                responses: []
            };

            let view = {
                currentIdx: 0,
                responseEditors : [],
                init: function () {
                    $('.btn_add_case').on('click', function () {
                        controller.addResponse();
                    });

                    $('#responseTabTitle').on('click', 'button', function () {
                        if ($(this).hasClass('btn_add_case')) {
                            controller.addResponse();
                        }
                    });

                    $('#responseTabContent').on('click', 'button', function () {
                        if ($(this).hasClass('btn_remove_case')) {
                            controller.removeResponse($(this).data("id"));
                        }

                        if ($(this).hasClass('btn_add_condition')) {
                            controller.addResponseCondition($(this).data("id"));
                        }

                        if ($(this).hasClass('btn_add_header')) {
                            controller.addResponseHeader($(this).data("id"));
                        }

                        if ($(this).hasClass('btn_remove_condition')) {
                            controller.removeResponseCondition($(this).data("id"), $(this).data("row"));
                        }

                        if ($(this).hasClass('btn_remove_header')) {
                            controller.removeResponseHeader($(this).data("id"), $(this).data("row"));
                        }
                    });

                    $('#responses').children().each(function () {
                        let response = {
                            conditions: [],
                            headers: []
                        };
                        //statusCode, delay, defaultResponse, body 로 끝나는 항목을 찾음
                        response.statusCode = $(this).find('input[name$="statusCode"]').val();
                        response.delay = $(this).find('input[name$="delay"]').val();
                        response.defaultResponse = $(this).find('input[name$="defaultResponse"]').val()==='true';
                        response.body = $(this).find('textarea[name$="body"]').val();

                        $(this).find('.response_conditions').children().each(function () {
                            let condition = {
                                type: $(this).find('select').val(),
                                key: $(this).find('input[name$="key"]').val(),
                                value: $(this).find('input[name$="value"]').val()
                            };
                            response.conditions.push(condition);
                        });

                        model.responses.push(response);

                        $(this).find('.response_headers').children().each(function () {
                            let header = {
                                key: $(this).find('input[name$="key"]').val(),
                                value: $(this).find('input[name$="value"]').val()
                            };
                            response.headers.push(header);
                        });
                    });
                    $('#responses').empty();
                    this.render();
                },
                renderCondition: function(i) {

                    $('#response_tab_' + i).find('.response_conditions').empty();
                    let conditions = $('#response_tab_' + i).find('.response_conditions');

                    for (let c = 0; c < model.responses[i].conditions.length; c++) {
                        let conditionTemplate = $('#conditionTemplate').children().find('tr').clone();
                        conditionTemplate.find('select').attr('name', 'responses[' + i + '].conditions[' + c + '].type');
                        conditionTemplate.find('input[name="key"]').attr('name', 'responses[' + i + '].conditions[' + c + '].key');
                        conditionTemplate.find('input[name="value"]').attr('name', 'responses[' + i + '].conditions[' + c + '].value');
                        conditionTemplate.find('button').attr("data-id", i);
                        conditionTemplate.find('button').attr("data-row", c);

                        conditionTemplate.find('select').val(model.responses[i].conditions[c].type);
                        conditionTemplate.find('input[name="responses[' + i + '].conditions[' + c + '].key"]').val(model.responses[i].conditions[c].key);
                        conditionTemplate.find('input[name="responses[' + i + '].conditions[' + c + '].value"]').val(model.responses[i].conditions[c].value);

                        conditionTemplate.find('select').on('change', function () {
                            model.responses[i].conditions[c].type = $(this).val();
                        });

                        conditionTemplate.find('input[name="responses[' + i + '].conditions[' + c + '].key"]').on('input', function () {
                            model.responses[i].conditions[c].key = $(this).val();
                        });

                        conditionTemplate.find('input[name="responses[' + i + '].conditions[' + c + '].value"]').on('input', function () {
                            model.responses[i].conditions[c].value = $(this).val();
                        });

                        $(conditions).append(conditionTemplate);
                    }
                },
                renderHeaders(i){

                    $('#response_tab_' + i).find('.response_headers').empty();
                    let headers = $('#response_tab_' + i).find('.response_headers');

                    for (let j = 0; j < model.responses[i].headers.length; j++) {
                        let headerTemplate = $('#responseHeaderTemplate').children().find('tr').clone();
                        headerTemplate.find('input[name="key"]').attr('name', 'responses[' + i + '].headers[' + j + '].key');
                        headerTemplate.find('input[name="value"]').attr('name', 'responses[' + i + '].headers[' + j + '].value');
                        headerTemplate.find('button').attr("data-id", i);
                        headerTemplate.find('button').attr("data-row", j);

                        headerTemplate.find('input[name="responses[' + i + '].headers[' + j + '].key"]').val(model.responses[i].headers[j].key);
                        headerTemplate.find('input[name="responses[' + i + '].headers[' + j + '].value"]').val(model.responses[i].headers[j].value);

                        headerTemplate.find('input[name="responses[' + i + '].headers[' + j + '].key"]').on('input', function () {
                            model.responses[i].headers[j].key = $(this).val();
                        });

                        headerTemplate.find('input[name="responses[' + i + '].headers[' + j + '].value"]').on('input', function () {
                            model.responses[i].headers[j].value = $(this).val();
                        });

                        $(headers).append(headerTemplate);
                    }
                },
                renderResponse(i){

                    this.renderResponseTabTitle();
                    let nodeCopy = $('#template').children().clone();

                    nodeCopy.attr('id', 'response_tab_' + i);
                    nodeCopy.attr('aria-labelledby', 'response_tab_' + i);
                    nodeCopy.attr('tabindex', i);

                    console.log(model.responses[i]);
                    nodeCopy.attr('class', 'tab-pane fade ' + (model.responses[i].defaultResponse? 'show active' : ''));
                    if (model.responses[i].defaultResponse) {
                        nodeCopy.find('.condition_name').text('기본 응답');
                        nodeCopy.find('.condition').attr('class', 'condition')
                        nodeCopy.find('.condition').attr('style', 'display: none;')
                    }else {
                        nodeCopy.find('.condition_name').text('조건 ' + (i + 1));
                    }
                    nodeCopy.find('.btn_remove_case').attr("data-id", i);
                    nodeCopy.find('.btn_add_condition').attr("data-id", i);
                    nodeCopy.find('.btn_add_header').attr("data-id", i);
                    nodeCopy.find('input[name="statusCode"]').attr('name', 'responses[' + i + '].statusCode');
                    nodeCopy.find('input[name="defaultResponse"]').attr('name', 'responses[' + i + '].defaultResponse');
                    nodeCopy.find('input[name="delay"]').attr('name', 'responses[' + i + '].delay');
                    nodeCopy.find('textarea[name="body"]').attr('name', 'responses[' + i + '].body');

                    nodeCopy.find('input[name="responses[' + i + '].statusCode"]').val(model.responses[i].statusCode);
                    nodeCopy.find('input[name="responses[' + i + '].defaultResponse"]').val(model.responses[i].defaultResponse);
                    nodeCopy.find('input[name="responses[' + i + '].delay"]').val(model.responses[i].delay);

                    let me = this;

                    require(['vs/editor/editor.main'], function () {
                        let editor = monaco.editor.create(nodeCopy.find(".response_body")[0], {
                            value: model.responses[i].body,
                            theme: 'vs-light',
                            automaticLayout: true
                        });

                        editor.onDidChangeModelContent(function (e) {
                            model.responses[i].body = editor.getValue();
                            nodeCopy.find('textarea[name="responses[' + i + '].body"]').val(editor.getValue());
                        });

                        me.responseEditors.push(editor);
                    });

                    nodeCopy.find('textarea[name="responses[' + i + '].body"]').val(model.responses[i].body);
                    nodeCopy.find('input[name="responses[' + i + '].statusCode"]').on('input', function () {
                        model.responses[i].statusCode = $(this).val();
                    });

                    nodeCopy.find('input[name="responses[' + i + '].delay"]').on('input', function () {
                        model.responses[i].delay = $(this).val();
                    });

                    $('#responseTabContent').append(nodeCopy);
                    if(view.currentIdx >= model.responses.length){
                        view.currentIdx = model.responses.length - 1;
                    }
                    $('#responseTabTitle li:eq(' + view.currentIdx + ') a').tab('show');

                },
                renderResponseTabTitle(){
                    $('#responseTabTitle').empty();
                    for (let i = 0; i < model.responses.length; i++) {
                        let tabButton = $('<a>').attr('class', 'nav-link'+ (model.responses[i].defaultResponse? ' active' : ''))
                            .attr('data-bs-toggle', 'tab')
                            .attr('type', 'button')
                            .attr('data-bs-target', '#response_tab_' + i)
                            .attr('role', 'tab')
                            .attr('aria-controls', 'response_tab_' + i)
                            .attr('aria-selected', 'false')
                            .text(model.responses[i].defaultResponse?'기본 응답':('조건 ' + i));

                        let li = $('<li>').attr('class', 'nav-item')
                            .attr('role','presentation')
                            .append(tabButton);

                        $('#responseTabTitle').append(li);
                    }
                    let tabButton = $('<button>').attr('class', 'nav-link btn_add_case')
                        .attr('type', 'button')
                        .attr('aria-selected', 'false')
                        .text("케이스 추가");

                    let li = $('<li>').attr('class', 'nav-item')
                        .attr('role','presentation')
                        .append(tabButton);

                    $('#responseTabTitle').append(li);
                },
                render: function () {
                    $('#responseTabContent').empty();

                    for (let i = 0; i < model.responses.length; i++) {
                        view.renderResponse(i);
                        view.renderCondition(i);
                        view.renderHeaders(i);
                    }
                }
            };

            let controller = {
                init: function () {
                    view.init();
                },
                addResponse: function () {
                    model.responses.push({
                        statusCode: 200,
                        delay: 0,
                        headers: [],
                        body: '',
                        conditions: [],
                    });

                    view.currentIdx = model.responses.length - 1;
                    view.renderResponse(view.currentIdx);
                },
                removeResponse: function (idx) {
                    if (model.responses[idx].defaultResponse) {
                        let message = '기본 응답은 삭제할 수 없습니다.';
                        $('.toast-body').text(message);
                        $('.toast').toast('show');
                        return;
                    }
                    model.responses.splice(idx, 1);
                    view.currentIdx = idx - 1;
                    view.render();
                },
                addResponseCondition: function (idx) {
                    model.responses[idx].conditions.push({
                        type: 'query',
                        key: '',
                        value: ''
                    });
                    view.currentIdx = idx;
                    view.renderCondition(idx);
                },
                removeResponseCondition: function (idx, conditionIdx) {
                    model.responses[idx].conditions.splice(conditionIdx, 1);
                    view.currentIdx = idx;
                    view.renderCondition(idx);
                },
                addResponseHeader: function (idx) {
                    model.responses[idx].headers.push({
                        key: '',
                        value: ''
                    });
                    view.currentIdx = idx;
                    view.renderHeaders(idx);
                },
                removeResponseHeader: function (idx, headerIdx) {
                    model.responses[idx].headers.splice(headerIdx, 1);
                    view.currentIdx = idx;
                    view.renderHeaders(idx);
                }
            }

            controller.init();

            let fnRegister = document.querySelector(".btn_register");

            fnRegister.addEventListener("click", function (event) {
                let form = document.getElementById("mockRouteForm");
                if (!form.checkValidity()) {
                    event.preventDefault()
                    event.stopPropagation()
                } else {
                    form.submit();
                }
                form.classList.add('was-validated');
            });

            let fnList = document.querySelector(".btn_list");

            fnList.addEventListener("click", function () {
                location.href = "[[@{/mgmt/routes/list_view.do}]]";
            });
        });
    </script>
</th:block>
</html>

