require.config({paths: {'vs': '/plugins/vs'}});


class APITester {


    constructor() {
        this.servers = [];
        this.apiTabTitleTarget = '#apiRequestTabTitle';
        this.apiTabContentTarget = '#apiRequestTabContent';
        this.collectionTarget = '#side_menubar';
        this.currentIndex = 0;
        this.apiRequests = [];  //탭 열린 API
        this.collections = [];  //API 컬렉션
        this.requestEditors = [];  //API request body editor
        this.responseEditors = []; //API response body editor

    }

    renderServers(selectedServer) {
        const optionsHtml = this.servers.map(server => `
            <option value="${server.id}" ${selectedServer === server.id ? 'selected' : ''}  data-path="${server.basePath}">${server.name}</option>
        `).join('');

        return `<select class="form-select server" name="server" required>
                <option value="">서버 선택</option>
                ${optionsHtml}</select>`;
    }

    basePath(serverId) {
        if (serverId === undefined || serverId === null) {
            return this.servers[0].basePath;
        }
        return this.servers.filter(server => server.id == serverId)[0].basePath; // == : 타입 비교 없이 값만 비교
    }

    apiRequestTemplate(apiRequest, index) {
        return `
        <div class="tab-pane fade mt-1 api_request" id="api_request_${apiRequest.id}" data-index="${index}">
            <div><span class="collection_name">${apiRequest.collectionName}</span> &gt; <span class="api_name">${apiRequest.name}</span></div>
            <div class="d-flex align-items-center api_request_info">
                <div class="form-floating col-md-1 me-1">
                    <select name="method" class="form-select method">
                        <option value="POST"    ${apiRequest.method === 'POST' ? 'selected' : ''}>POST</option>
                        <option value="GET"     ${apiRequest.method === 'GET' ? 'selected' : ''}>GET</option>
                        <option value="PUT"     ${apiRequest.method === 'PUT' ? 'selected' : ''}>PUT</option>
                        <option value="DELETE"  ${apiRequest.method === 'DELETE' ? 'selected' : ''}>DELETE</option>
                        <option value="CONNECT" ${apiRequest.method === 'CONNECT' ? 'selected' : ''}>CONNECT</option>
                        <option value="HEAD"    ${apiRequest.method === 'HEAD' ? 'selected' : ''}>HEAD</option>
                        <option value="OPTIONS" ${apiRequest.method === 'OPTIONS' ? 'selected' : ''}>OPTIONS</option>
                        <option value="TRACE"   ${apiRequest.method === 'TRACE' ? 'selected' : ''}>TRACE</option>
                        <option value="PATCH"   ${apiRequest.method === 'PATCH' ? 'selected' : ''}>PATCH</option>
                    </select>
                    <label class="form-label must">Method</label>
                </div>
                <div class="form-floating col-md-2 me-1">
                    ${this.renderServers(apiRequest.server)}
                    <label class="form-label must">Server</label>
                </div>
                <div class="form-floating col-md-2 me-1">
                    <div class="form-floating col-md">
                        <input type="text" name="basePath" class="form-control" value="${this.basePath(apiRequest.server)}" readonly>
                        <label class="must">base path</label>
                    </div>
                </div>
                <div class="input-group col-md me-1">
                    <div class="form-floating col-md">
                        <input type="text" name="path" class="form-control path" value="${apiRequest.path}" placeholder="호출할 경로 (/부터 입력)"
                               required>
                        <label class="must">Path</label>
                    </div>
                    <button class="btn btn-primary send">Send</button>
                </div>
                <button class="btn btn-primary save" data-index="${index}" style="height: 58px;">저장</button>
            </div>
            <ul class="nav nav-tabs mt-1" role="tablist">
                <li class="nav-item" role="presentation">
                    <button class="nav-link btn_request_body_tab" data-bs-toggle="tab"
                            type="button" role="tab" aria-controls="requestBody" data-bs-target="#requestBodyTab_${apiRequest.id}"
                            aria-selected="false">Body
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link btn_request_param_tab" data-bs-toggle="tab" 
                            type="button" role="tab" aria-controls="paramTab" data-bs-target="#requestParamTab_${apiRequest.id}"
                            aria-selected="true">Param
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link btn_request_header_tab" data-bs-toggle="tab"
                            type="button" role="tab" aria-controls="requestHeader" data-bs-target="#requestHeaderTab_${apiRequest.id}"
                            aria-selected="false">Header
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link btn_variables_tab" data-bs-toggle="tab"
                            type="button" role="tab" aria-controls="variables" data-bs-target="#variablesTab_${apiRequest.id}"
                            aria-selected="false">Variables
                    </button>
                </li>
            </ul>
            <div class="tab-content border-bottom" style="min-height: 300px;">
                <div class="tab-pane fade show request_param_tab" role="tabpanel" id="requestParamTab_${apiRequest.id}"
                     aria-labelledby="requestParams-tab">
                    <table class="table">
                        <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">이름</th>
                            <th>값</th>
                            <th>
                                <button type="button" class="btn btn-secondary btn-sm btn_add_query">추가</button>
                            </th>
                        </tr>
                        </thead>
                        <tbody class="query_params">
                            ${this.renderParams(apiRequest.queryParams)}
                        </tbody>
                    </table>
                </div>
                <div class="tab-pane fade request_header_tab" role="tabpanel" id="requestHeaderTab_${apiRequest.id}"
                     aria-labelledby="requestHeader-tab">
                    <table class="table">
                        <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">이름</th>
                            <th scope="col">값</th>
                            <th scope="col">
                                <button type="button" class="btn btn-secondary btn-sm btn_add_header">추가</button>
                            </th>
                        </tr>
                        </thead>
                        <tbody class="request_headers">
                            ${this.renderHeaders(apiRequest.headers)}
                        </tbody>
                    </table>
                </div>
                <div class="tab-pane fade variables_tab" role="tabpanel" id="variablesTab_${apiRequest.id}"
                     aria-labelledby="variables-tab">
                    <table class="table">
                        <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">키</th>
                            <th scope="col">값</th>
                            <th scope="col">
                                <button type="button" class="btn btn-secondary btn-sm btn_add_variables">추가
                                </button>
                            </th>
                        </tr>
                        </thead>
                        <tbody class="variables">
                            ${this.renderVariables(apiRequest.variables)}
                        </tbody>
                    </table>
                </div>
                <div class="tab-pane fade request_body_tab" role="tabpanel" id="requestBodyTab_${apiRequest.id}"
                     aria-labelledby="requestBody-tab">
                    <select class="form-select mt-1 request_body_type" name="request_type">
                        <option value="json">json</option>
                        <option value="xml">xml</option>
                        <option value="text/plain">text/plain</option>
                    </select>
                    <div class="request_body mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
                </div>
            </div>
            <div class="mt-1">
                <span>Response</span>
                <span class="response_status"></span>
                <span class="response_time"></span>
                <span class="response_size"></span>
            </div>
            <ul class="nav nav-tabs mt-1" role="tablist">
                <li class="nav-item" role="presentation">
                    <button class="nav-link active" data-bs-toggle="tab" data-bs-target="#responseBodyTab_${apiRequest.id}" type="button" role="tab" aria-controls="responseBody" aria-selected="false">Body</button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" data-bs-toggle="tab" data-bs-target="#responseHeaderTab_${apiRequest.id}" type="button" role="tab" aria-controls="responseHeader" aria-selected="false">Header</button>
                </li>
            </ul>
            <div class="tab-content border-bottom" style="min-height: 250px;">
                <div class="tab-pane fade show active" id="responseBodyTab_${apiRequest.id}" role="tabpanel"
                     aria-labelledby="requestParams-tab">
                    <div class="response_body mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
                </div>
                <div class="tab-pane fade" id="responseHeaderTab_${apiRequest.id}" role="tabpanel"
                     aria-labelledby="requestParams-tab">
                    <table class="table">
                        <thead>
                        <tr>
                            <th scope="col">이름</th>
                            <th scope="col">값</th>
                        </tr>
                        </thead>
                        <tbody class="response_headers">
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        `;
    }

    queryParamTemplate(queryParam, index) {
        return `
            <tr data-index="${index}">
                <td>
                    <div class="form-check">
                        <input class="form-check-input" type="checkbox" name="queryParams[${index}].enabled" ${queryParam.enabled ? 'checked' : ''} />
                    </div>
                </td>
                <td>
                    <input class="form-control" type="text" name="queryParams[${index}].key" value="${queryParam.key}"/>
                </td>
                <td>
                    <input class="form-control" type="text" name="queryParams[${index}].value" value="${queryParam.value}"/>
                </td>
                <td>
                    <button type="button" class="btn btn-secondary btn-sm btn_remove_query">제거</button>
                </td>
            </tr>
        `;
    }

    variableTemplate(variable, index) {
        return `
            <tr data-index="${index}">
                <td>
                    <div class="form-check">
                        <input class="form-check-input" type="checkbox" name="variables[${index}].enabled" ${variable.enabled ? 'checked' : ''} />
                    </div>
                </td>
                <td>
                    <input class="form-control" type="text" name="variables[${index}].key" value="${variable.key}"/>
                </td>
                <td>
                    <input class="form-control" type="text" name="variables[${index}].value" value="${variable.value}"/>
                </td>
                <td>
                    <button type="button" class="btn btn-secondary btn-sm btn_remove_variable">제거</button>
                </td>
            </tr>
        `;
    }

    headerTemplate(header, index) {
        return `
            <tr data-index="${index}">
                <td>
                    <div class="form-check">
                        <input class="form-check-input" type="checkbox" name="headers[${index}].enabled" ${header.enabled ? 'checked' : ''} />
                    </div>
                </td>
                <td>
                    <input class="form-control" type="text" name="headers[${index}].key" value="${header.key}"/>
                </td>
                <td>
                    <input class="form-control" type="text" name="headers[${index}].value" value="${header.value}"/>
                </td>
                <td>
                    <button type="button" class="btn btn-secondary btn-sm btn_remove_header">제거</button>
                </td>
            </tr>
        `;
    }

    responseHeaderTemplate(header, index) {
        return `
            <tr data-id="${index}">
                <td>
                    <input class="form-control" type="text" name="model.responseModel.headers[${index}].key" value="${header.key}" readonly/>
                </td>
                <td>
                    <input class="form-control" type="text" name="model.responseModel.headers[${index}].value" value="${header.value}" readonly/>
                </td>
            </tr>
        `;
    }

    collectionTemplate(collection, index) {
        return `
        <li id="collection_${index}" class="collection" data-index="${index}">
            <div class="d-flex justify-content-between">
                <button class="btn d-inline-flex align-items-center rounded normal"
                        data-bs-toggle="collapse"
                        data-bs-target="#btn_collection_${index}" aria-expanded="false" aria-current="false">${collection.name}
                </button>
                <div class="d-flex justify-content-between">
                    <button class="p-1 reset-button edit_collection" data-collection="${collection.id}"><i class="fa fa-sharp fa-file-edit"></i></button>
                    <button class="p-1 reset-button delete_collection" data-collection="${collection.id}"><i class="fa fa-sharp fa-trash-can"></i></button>
                </div>
            </div>
            <div class="collapse" id="btn_collection_${index}">
                <ul class="list-unstyled fw-normal pb-1 small">
                    ${collection.apis.map((api, apiIndex) => this.collectionApiTemplate(api, apiIndex, collection.id)).join('')}
                </ul>
            </div>
        </li>
        `;
    }

    collectionApiTemplate(api, apiIndex, collectionId) {
        return `
        <li class="d-flex justify-content-between " data-collection="${collectionId}" data-id="${api.id}" data-index="${apiIndex}">
                <a href="#" class="d-inline-flex align-items-center rounded open_api_request">${api.name}</a>
                <div class="d-flex justify-content-between">
                    <button class="p-1 reset-button edit_api_request"><i class="fa fa-sharp fa-file-edit"></i></button>
                    <button class="p-1 reset-button delete_api_request"><i class="fa fa-trash-can"></i></button>
                </div>
            </li>
        `;
    }

    init(servers) {
        if (servers) {
            this.servers = servers;
        }
        this.bindEvents();
        this.loadCollections();
    }

    bindEvents() {
        const events = [
            {selector: '.btn_add_header', action: this.addHeader.bind(this)},
            {selector: '.btn_remove_header', action: this.removeHeader.bind(this)},
            {selector: '.btn_add_query', action: this.addQueryParam.bind(this)},
            {selector: '.btn_remove_query', action: this.removeQueryParam.bind(this)},
            {selector: '.btn_add_variables', action: this.addVariable.bind(this)},
            {selector: '.btn_remove_variable', action: this.removeVariable.bind(this)},

            {selector: '.send', action: this.sendApiRequest.bind(this)},
            {selector: '.save', action: this.saveAPIRequest.bind(this)},
            {selector: '.save_collection', action: this.addCollection.bind(this)},
            {selector: '#cancel-ajax', action: this.cancelAjaxRequest.bind(this)},
            {selector: '#new_collection', action: this.showNewCollectionModal.bind(this)},
            {selector: '#new_request', action: this.showNewApiRequestModal.bind(this)},
            {selector: '.edit_collection', action: this.showCollectionEditModal.bind(this)},
            {selector: '.delete_collection', action: this.showCollectionDeleteModal.bind(this)},
            {selector: '.confirm_delete', action: this.removeCollection.bind(this)},
            {selector: '.add_new_request', action: this.addAPIRequest.bind(this)},
            {selector: '.edit_api_request', action: this.showEditNameModal.bind(this)},
            {selector: '.delete_api_request', action: this.showDeleteApiRequestModal.bind(this)},
            {selector: '.open_api_request', action: this.openApiRequest.bind(this)},
            {selector: '.confirm_delete_api', action: this.deleteApiRequest.bind(this)},
            {selector: '.close_tab', action: this.closeTab.bind(this)}

        ];

        for (let event of events) {
            $(document).on('click', event.selector, event.action);
        }

        $(document).on('input',  '.query_params input', this.handleUIUpdate.bind(this));
        $(document).on('input',  '.query_params input', this.buildPath.bind(this));
        $(document).on('change', '.query_params input', this.handleUIUpdate.bind(this));
        $(document).on('change', '.query_params input', this.buildPath.bind(this));
        $(document).on('input',  '.path', this.parseParam.bind(this));
        $(document).on('change', '.request_headers input', this.handleUIUpdate.bind(this));
        $(document).on('change', '.variables input', this.handleUIUpdate.bind(this));
        $(document).on('change', '.api_request_info select, .api_request_info input', this.handleUIUpdate.bind(this));
        $(document).on('change', '.api_request_info select', this.handleUpdateServer.bind(this));


    }

    showCollectionDeleteModal(event) {
        const collectionId = $(event.currentTarget).closest('button').data('collection');
        $('#confirm_delete_modal').find('.confirm_delete').data('id', collectionId);
        $('#confirm_delete_modal').modal('show');
    }

    showCollectionEditModal(event) {
        const me = this;
        const collectionId = $(event.currentTarget).closest('button').data('collection');
        const collection = this.collections.filter(function (collection) {
            return collection.id === collectionId;
        })[0];

        $('#edit_name_modal').find('input').val('');
        $('#edit_name_modal').modal('show');

        let saveBtn = $('#edit_name_modal').find('button.change_name');
        saveBtn.off('click');

        saveBtn.on('click', function () {
            collection.name = $('#edit_name_modal').find('input').val();
            me.saveCollection(collection.id, collection.name);
            me.renderCollections();
            $('#edit_name_modal').modal('hide');
        });
    }

    showDeleteApiRequestModal(event) {
        let collectionId = $(event.currentTarget).closest('li').data('collection');
        let apiId = $(event.currentTarget).closest('li').data('id');
        console.log('apiId: ' + apiId);
        $('#confirm_delete_api_modal').find('.confirm_delete_api').data('id', apiId);
        $('#confirm_delete_api_modal').find('.confirm_delete_api').data('collection', collectionId);
        $('#confirm_delete_api_modal').modal('show');
    }

    showNewApiRequestModal(event) {
        if (this.collections.length == 0) {
            alert('새로운 컬렉션을 추가해 주세요.');
            return;
        }
        $('#new_api_request_modal').modal('show');
    }

    showNewCollectionModal(event) {
        $('#new_collection_modal').find('input').val('');
        $('#new_collection_modal').modal('show');
    }

    showEditNameModal(event) {
        const me = this;
        const apiId = $(event.currentTarget).closest('li').data('id');
        const collectionId = $(event.currentTarget).closest('li').data('collection');

        const collection = this.collections.filter(function (collection) {
            return collection.id === collectionId;
        })[0];

        let apiRequest = collection.apis.filter(function (api) {
            return api.id === apiId;
        })[0];

        apiRequest.collectionId = collectionId;

        let saveBtn = $('#edit_name_modal').find('button.change_name');
        saveBtn.off('click');
        saveBtn.on('click', function () {
            apiRequest.name = $('#edit_name_modal').find('input').val();
            me.changeAPIName(apiRequest);
            me.renderCollections();
            $('#edit_name_modal').modal('hide');

            //탭이 열려 있으면, 닫았다가 다시 열어야 함.
            me.renderTabHeader();
            me.renderTabContent(apiRequest.index);

        });
        $('#edit_name_modal').find('input').val('');
        $('#edit_name_modal').modal('show');
    }

    getFieldValue(element) {
        if ($(element).is('select') || $(element).is('input[type="text"]')) {
            return $(element).val();
        }
        if ($(element).is('input[type="checkbox"]')) {
            return $(element).is(':checked');
        }
    }

    handleUIUpdate(event) {
        if (event) {
            event.preventDefault();
            const element = event.currentTarget;
            const fieldName = $(element).attr('name');
            //console.log(fieldName);
            const newValue = this.getFieldValue(element);
            //console.log(newValue);

            const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
            let model = this.apiRequests[tabIndex];

            if (fieldName !== '') {
                _.set(model, fieldName, newValue);
            }
            //console.log(model);
        }
    }

    handleUpdateServer(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        let model = this.apiRequests[tabIndex];
        let target = $('#api_request_' + model.id);
        //console.log('model.server: ' + model.server);
        target.find('input[name="basePath"]').val(this.basePath(model.server));
    }

    renderParams(params) {
        return params.map((param, index) => this.queryParamTemplate(param, index)).join('');
    }

    renderVariables(variables) {
        return variables.map((variable, index) => this.variableTemplate(variable, index)).join('');
    }

    renderHeaders(headers) {
        return headers.map((header, index) => this.headerTemplate(header, index)).join('');
    }

    renderTabHeader() {
        //console.log('renderTabHeader');
        let apiRequestTabTitle = $('#apiRequestTabTitle');
        apiRequestTabTitle.empty();

        for (let idx = 0; idx < this.apiRequests.length; idx++) {
            let li = `<li class="nav-item" role="presentation">
                        <button class="nav-link" id="api_request_tab_${this.apiRequests[idx].id}" data-index="${idx}" data-bs-toggle="tab" type="button" role="tab" aria-controls="api_request_${this.apiRequests[idx].id}" data-bs-target="#api_request_${this.apiRequests[idx].id}" aria-selected="false">${this.apiRequests[idx].name}
                            <span class="close_tab"><i class="fa fa-light fa-close"></i></span>
                        </button>
                    </li>`;
            apiRequestTabTitle.append(li);
        }
    }

    renderTabContent(index) {
        var me = this;
        //console.log('renderTabContent: ' + index);
        let apiRequestTabContent = $(this.apiTabContentTarget);
        let model = this.apiRequests[index];

        apiRequestTabContent.append(this.apiRequestTemplate(model, index));

        this.openTab(model.id);
        let target = $('#api_request_' + model.id);

        require(['vs/editor/editor.main'], function () {
            let requestBodyEditor = monaco.editor.create(target.find(".request_body")[0], {
                value: model.requestBody,
                language: 'json',
                theme: 'vs-light',
                automaticLayout: true
            });
            me.requestEditors.push(requestBodyEditor);
            target.find(".request_body")[0].addEventListener('shown.bs.tab', function () {
                me.requestEditors[index].layout();
            });

            me.requestEditors[index].onDidChangeModelContent(function (e) {
                model.requestBody = requestBodyEditor.getValue();
            });

            target.find('.request_body_type').on('change', function () {
                let model = requestBodyEditor.getModel();
                monaco.editor.setModelLanguage(model, $(this).val());
            });

            let responseBodyEditor = monaco.editor.create(target.find(".response_body")[0], {
                value: '',
                language: 'json',
                theme: 'vs-light',
                automaticLayout: true
            });
            me.responseEditors.push(responseBodyEditor);
        });
    }

    renderResponse(tabIndex) {
        //console.log('renderResponse: ' + tabIndex);
        let model = this.apiRequests[tabIndex];
        let target = $('#api_request_' + model.id);
        target.find('.response_headers').empty();
        target.find(".response_status").empty();

        //console.log(model.responseModel);

        try {
            const parsedJson = JSON.parse(model.responseModel.body);
            const formattedJson = JSON.stringify(parsedJson, null, 2);
            this.responseEditors[tabIndex].setValue(formattedJson);
        } catch(e) {
            this.responseEditors[tabIndex].setValue(model.responseModel.body);
        }
        if(model.responseModel && model.responseModel.headers) {
            for (let i = 0; i < model.responseModel.headers.length; i++) {
                target.find('.response_headers').append(this.responseHeaderTemplate(model.responseModel.headers[i], i));
            }
        }

        target.find(".response_status").text("status: " + model.responseModel.status);
        target.find(".response_time").text("time: " + model.responseModel.time + "ms");
        target.find(".response_size").text("size: " + model.responseModel.size + "bytes");

    }


    renderCollections() {
        let select = $('#modal_collection');
        let sidemenu = $(this.collectionTarget);
        select.empty();
        sidemenu.empty();

        for (let i = 0; i < this.collections.length; i++) {
            sidemenu.append(this.renderCollection(this.collections[i], i));
            let option = $('<option>');
            option.attr('value', this.collections[i].id);
            option.text(this.collections[i].name);
            select.append(option);
        }
    }

    renderCollection(collection, index) {
        return this.collectionTemplate(collection, index);
    }

    openTab(id) {
        //console.log('openTab: ' + id);
        try {
            $(`#api_request_tab_${id}`).tab('show'); // API request 탭 활성화
        } catch (e) {
            //console.log(e);
        }

        //console.log('openTab, api_request: ' + id);
        try {
            $(`#api_request_${id}`).find('.btn_request_body_tab').tab('show');  // Body 탭 활성화
            //console.log('openTab, done: ' + id);
        } catch (e) {
            //console.log(e);
        }
    }

    addHeader(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        let model = this.apiRequests[tabIndex];
        model.headers.push({
            enabled: true,
            key: '',
            value: ''
        });
        this.renderHeaderView(tabIndex);
    }

    removeHeader(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        const index = $(event.currentTarget).closest('tr').data('index');
        let model = this.apiRequests[tabIndex];
        model.headers.splice(index, 1);
        this.renderHeaderView(tabIndex);
    }

    renderHeaderView(tabIndex) {
        let model = this.apiRequests[tabIndex];
        //console.log(model);
        let target = $('#api_request_' + model.id);
        target.find('.request_headers').empty();
        target.find('.request_headers').append(this.renderHeaders(model.headers));
    }


    addQueryParam(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        //console.log('addQueryParam');
        let model = this.apiRequests[tabIndex];
        model.queryParams.push({
            enabled: true,
            key: '',
            value: ''
        });

        this.renderQueryParamsView(tabIndex);
    }

    removeQueryParam(event) {
        //console.log('removeQueryParam');
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        const index = $(event.currentTarget).closest('tr').data('index');
        let model = this.apiRequests[tabIndex];
        model.queryParams.splice(index, 1);
        this.renderQueryParamsView(tabIndex);
    }

    renderQueryParamsView(tabIndex) {
        let model = this.apiRequests[tabIndex];

        let target = $('#api_request_' + model.id);
        target.find('.query_params').empty();
        target.find('.query_params').append(this.renderParams(model.queryParams));
    }

    addVariable(event) {
        //console.log('addVariable');
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        let model = this.apiRequests[tabIndex];
        model.variables.push({
            enabled: true,
            key: '',
            value: ''
        });
        this.renderVariablesView(tabIndex);
    }

    removeVariable(event) {
        //console.log('removeVariable');
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        const index = $(event.currentTarget).closest('tr').data('index');
        let model = this.apiRequests[tabIndex];
        model.variables.splice(index, 1);
        this.renderVariablesView(tabIndex);
    }

    renderVariablesView(tabIndex) {
        let model = this.apiRequests[tabIndex];
        //console.log(model);
        let target = $('#api_request_' + model.id);
        target.find('.variables').empty();
        target.find('.variables').append(this.renderVariables(model.variables));
    }
    parseParam(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        let model = this.apiRequests[tabIndex];
        model.path = $(event.currentTarget).val();
        //console.log(model.path);
        model.queryParams = [];
        let queryString = model.path.split('?')[1];
        //console.log('parseParam:' + queryString);
        if (queryString) {
            let queryParamArray = queryString.split('&');
            for (let i = 0; i < queryParamArray.length; i++) {
                let queryParam = queryParamArray[i].split('=');

                model.queryParams.push({
                    enabled: true,
                    key: queryParam[0],
                    value: (queryParam[1] === undefined ? '' : queryParam[1])
                });
            }
            this.renderQueryParamsView(tabIndex);
        }
    }
    buildPath(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        let model = this.apiRequests[tabIndex];
        let queryString = model.path.split('?')[0];
        if (model.queryParams.length > 0) {
            queryString += '?';
        }
        for (let i = 0; i < model.queryParams.length; i++) {
            if (!model.queryParams[i].enabled) {
                continue;
            }
            queryString += model.queryParams[i].key + '=' + model.queryParams[i].value;
            if (i < model.queryParams.length - 1) {
                queryString += '&';
            }
        }
        model.path = queryString;
        $('#api_request_' + model.id).find('.path').val(model.path);
    }

    showLoadingOverlay() {
        $("#loading-overlay").show();
    }

    hideLoadingOverlay() {
        $("#loading-overlay").hide();
    }

    sendApiRequest(event) {
        const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
        const me = this;

        let model = this.apiRequests[tabIndex];
        let target = $('#api_request_' + model.id);
        target.find('.response_headers').empty();
        this.responseEditors[tabIndex].setValue('');
        let startTime = new Date().getTime();

        if (model.path !== '') {
            this.showLoadingOverlay();
            this.currentAjaxRequest = $.ajax({
                url: '/mgmt/api/test.do',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(model),
                success: function (data) {
                    model.responseModel.status = data.status;
                    model.responseModel.body = data.body;
                    model.responseModel.headers = data.headers;
                    model.responseModel.size = data.size;
                },
                error: function (response, textStatus, errorThrown) {
                    me.hideLoadingOverlay();
                    $('.toast-body').text(response.responseJSON.error);
                    $('.toast').toast('show');
                },
                complete: function () {
                    let endTime = new Date().getTime();
                    model.responseModel.time = endTime - startTime;
                    me.renderResponse(tabIndex);
                    me.hideLoadingOverlay();
                }
            });
        }
    }


    loadCollections() {
        const me = this;
        this.currentAjaxRequest = $.ajax({
            url: '/mgmt/collections/list.do',
            type: 'GET',
            contentType: 'application/json',
            success: function (data) {
                me.collections = data.map(collection => {
                    if (collection.apis) {
                        collection.apis = collection.apis.map(api => ({...api, collectionId: collection.id}));
                    }
                    return collection;
                });
            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.renderCollections();
                me.hideLoadingOverlay();
            }
        });
    }

    addCollection(event) {
        const name = $('#new_collection_name').val();
        const me = this;
        me.showLoadingOverlay();
        this.currentAjaxRequest = $.ajax({
            url: '/mgmt/collections/create.do',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({name: name}),
            success: function (data) {

            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.loadCollections();
                me.hideLoadingOverlay();
                $('#new_collection_modal').modal('hide');
            }
        });
    }

    saveCollection(id, name) {
        const me = this;
        me.showLoadingOverlay();
        this.currentAjaxRequest = $.ajax({
            url: '/mgmt/collections/update.do',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({id: id, name: name}),
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.loadCollections();
                me.hideLoadingOverlay();
                $('#new_collection_modal').modal('hide');
            }
        });
    }

    removeCollection(event) {
        let collectionId = $(event.currentTarget).closest('button').data('id');
        const me = this;
        me.showLoadingOverlay();
        this.currentAjaxRequest = $.ajax({
            url: '/mgmt/collections/delete.do',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({id: collectionId}),
            success: function () {
            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.loadCollections();
                me.hideLoadingOverlay();
                $('#confirm_delete_modal').modal('hide');
            }
        });
    }

    changeAPIName(model) {
        const me = this;
        me.showLoadingOverlay();
        this.currentAjaxRequest = $.ajax({
            url: `/mgmt/collections/${model.collectionId}/apis/save.do`,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(model),
            success: function (data) {
                let message = '저장되었습니다.';
                $('.toast-body').text(message);
                $('.toast').toast('show');
            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.hideLoadingOverlay();
            }
        });
    }

    saveAPIRequest(event) {
        const me = this;
        const index = $(event.currentTarget).data('index');
        let model = this.apiRequests[index];
        me.showLoadingOverlay();

        //console.log('model.collectionId: '+ model.collectionId);

        this.currentAjaxRequest = $.ajax({
            url: `/mgmt/collections/${model.collectionId}/apis/save.do`,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(model),
            success: function (data) {
                let message = '저장되었습니다.';
                $('.toast-body').text(message);
                $('.toast').toast('show');
            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.hideLoadingOverlay();
            }
        });
    }

    addAPIRequest(event) {
        const collectionId = $('#modal_collection').val();
        let me = this;
        let newApi = {
            id: '',
            server: null,
            method: 'GET',
            name: 'New Request',
            path: '',
            headers: [],
            queryParams: [],
            variables: [],
            requestBody: '',
            collectionId: collectionId,
            responseModel: {
                status: 0,
                time: 0,
                size: 0,
                headers: [],
                ody: ''
            }
        };

        this.currentAjaxRequest = $.ajax({
            url: `/mgmt/collections/${collectionId}/apis/save.do`,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(newApi),
            success: function (data) {
                newApi.id = data;
            },
            error: function (response, textStatus, errorThrown) {
                me.hideLoadingOverlay();
                $('.toast-body').text(response.responseJSON.error);
                $('.toast').toast('show');
            },
            complete: function () {
                me.loadCollections();
                me.apiRequests.push(newApi);
                me.currentIndex = me.apiRequests.length - 1;

                me.renderTabHeader();
                me.renderTabContent(me.currentIndex);

                me.hideLoadingOverlay();
                $('#new_api_request_modal').modal('hide');
            }
        });
    }

    cancelAjaxRequest() {
        if (this.currentAjaxRequest) {
            this.currentAjaxRequest.abort();
            this.hideLoadingOverlay();
        }
    }

    openApiRequest(event) {
        const collectionId = $(event.currentTarget).closest('li').data('collection');
        const apiId = $(event.currentTarget).closest('li').data('id');

        const collection = this.collections.filter(function (collection) {
            return collection.id === collectionId;
        })[0];
        let selectedApi = collection.apis.filter(function (api) {
            return api.id === apiId;
        })[0];

        if (selectedApi) {
            selectedApi.collectionId = collectionId;
            selectedApi.collectionName = collection.name;
            let tab = this.apiRequests.filter(function (api) {
                return api.id === selectedApi.id;
            })[0];

            if (!selectedApi.responseModel) {
                selectedApi.responseModel = {
                    status: 0,
                    time: 0,
                    size: 0,
                    headers: [],
                    body: ''
                };
            }

            if (tab) {
                this.currentIndex = this.apiRequests.findIndex(function (api) {
                    return api.id === selectedApi.id;
                });
                this.openTab(selectedApi.id);

            } else {
                this.apiRequests.push(selectedApi);
                this.currentIndex = this.apiRequests.length - 1;
                this.renderTabHeader();
                this.renderTabContent(this.currentIndex);
            }
        }
    }

    deleteApiRequest(event) {
        let collectionId = $(event.currentTarget).closest('button').data('collection');
        let apiId = $(event.currentTarget).closest('.confirm_delete_api').data('id');
        console.log(event.currentTarget);
        console.log($(event.currentTarget));
        console.log('deleteApiRequest: ' + apiId);
        console.log('collectionId: ' + collectionId);
        let apiIndex = this.apiRequests.findIndex(function (api) {
            return api.id === apiId;
        });
        console.log(apiIndex);
        if(apiIndex >= 0){
            this.closeTabWithApiIndex(apiIndex);
        }
        const me = this;
        this.currentAjaxRequest = $.ajax({
            url: `/mgmt/collections/${collectionId}/apis/delete.do`,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({id: apiId}),
            success: function (data) {
            },
            error: function (response, textStatus, errorThrown) {
                $('.toast-body').text(response.responseJSON.error);
                me.hideLoadingOverlay();
            },
            complete: function () {
                me.hideLoadingOverlay();
                me.loadCollections();
                $('#confirm_delete_api_modal').modal('hide');
                // $('#confirm_delete_api_modal').find('.confirm_delete_api').removeAttr('data-id');
                // $('#confirm_delete_api_modal').find('.confirm_delete_api').removeAttr('data-collection');
            }
        });
    }

    closeTabWithApiIndex(index) {
        if (index !== undefined){
            //console.log('closeTabWithApiIndex: ' + index);
            const model = this.apiRequests[index];
            this.apiRequests.splice(index, 1);

            let apiRequestTabTitle = $(this.apiTabTitleTarget);
            apiRequestTabTitle.empty();
            this.renderTabHeader();
            $(`#api_request_${model.id}`).remove();
            $(`#apiRequestTabTitle li:eq(${this.apiRequests.length - 1}) button`).tab('show');
        }
    }
    closeTab(event) {
        let index = $(event.currentTarget).closest('button').data('index');
        //console.log('closeTab: ' + index);
        this.closeTabWithApiIndex(index);
    }
}