package com.tsi.api.server.controller;

import com.tsi.api.server.controller.result.*;
import com.tsi.api.server.error.TscSsipApiErrorCode;
import com.tsi.api.server.service.TscSsipAppService;
import com.tsi.api.server.util.ApiUtils;
import com.tsi.api.server.vo.ApiInvokeVo;
import com.tsi.api.server.vo.DeviceInfo;
import com.tsi.api.server.vo.VersionVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;

@Slf4j
@RestController
public class TscSsipAppController {

    private final String NAVI_NODE_STATUS     = "/app/nodes/{deviceId}";
    private final String NAVI_DEVICE_AUTH     = "/app/auth/{deviceId}";
    private final String NAVI_DEVICE_REGISTER = "/app/devices";
    private final String NAVI_DOWNLOADS       = "/app/download/{fileName}";
    private final String NAVI_API_UUID        = "/app/uuid";

    private final TscSsipAppService tscNaviApiService;

    public TscSsipAppController(TscSsipAppService tscNaviApiService) {
        this.tscNaviApiService = tscNaviApiService;
    }

    @GetMapping(value = {NAVI_NODE_STATUS}, produces = {"application/json; charset=utf8"})
    public ResponseEntity<AbstractTscSsipApiResult> getNodeStatus(@PathVariable("deviceId") String deviceId, HttpServletRequest request) {

        final String apiId = NAVI_NODE_STATUS;
        final String remoteIP = ApiUtils.getRemoteIP(request);
        log.info("{}, {}, {}", apiId, remoteIP, deviceId);

        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
                .apiId(apiId)
                .apiToken(deviceId)
                .ipAddr(remoteIP)
                .error(TscSsipApiErrorCode.SUCCESS.getCode())
                .build();

        try {
            TscSsipApiErrorCode authorizedInfo = this.tscNaviApiService.getAuthorizedInfo(apiId, deviceId, remoteIP);
            if (authorizedInfo != TscSsipApiErrorCode.SUCCESS) {
                // api token 인증 오류
                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, deviceId, authorizedInfo.getCode(), authorizedInfo.getMessage());
                apiInvokeVo.setError(authorizedInfo.getCode());
                this.tscNaviApiService.insertInvokeHs(apiInvokeVo, false);
                TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
                return new ResponseEntity<> (error, HttpStatus.UNAUTHORIZED);
            }
        }
        catch (Exception e) {
            log.error("getNodeStatus: {}", e.getMessage());
            // 데이터베이스 오류
            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
        }


        TscNaviApiResultNodeStatusInfo result = new TscNaviApiResultNodeStatusInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
        result.setStatusList(tscNaviApiService.getNodeStatusList());
        result.setCount(result.getStatusList().size());

        // 이력저장
        this.tscNaviApiService.insertInvokeHs(apiInvokeVo, false);
        log.info("NodeStatus: {}, {}", deviceId, result.toString());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @GetMapping(value = {NAVI_DEVICE_AUTH}, produces = {"application/json; charset=utf8"})
    public ResponseEntity<AbstractTscSsipApiResult> getDeviceAuthInfo(@PathVariable("deviceId") String deviceId, HttpServletRequest request) {

        final String apiId = NAVI_DEVICE_AUTH;
        final String remoteIP = ApiUtils.getRemoteIP(request);
        log.info("{}, {}, {}", apiId, remoteIP, deviceId);

        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
                .apiId(apiId)
                .apiToken(deviceId)
                .ipAddr(remoteIP)
                .error(TscSsipApiErrorCode.SUCCESS.getCode())
                .build();

        TscSsipApiErrorCode authorizedInfo = null;
        TscNaviApiResultAuthInfo result = null;
        try {
            authorizedInfo = this.tscNaviApiService.getAuthorizedInfo(apiId, deviceId, remoteIP);
        /*if (authorizedInfo == TscSsipApiErrorCode.UNREGISTERED_APITOKEN) {
            // api token 인증 오류
            log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, deviceId, authorizedInfo.getCode(), authorizedInfo.getMessage());
            apiInvokeVo.setError(authorizedInfo.getCode());
            this.tscNaviApiService.insertInvokeHs(apiInvokeVo);
            TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
            return new ResponseEntity<> (error, HttpStatus.UNAUTHORIZED);
        }*/

            result = new TscNaviApiResultAuthInfo(authorizedInfo.getCode(), authorizedInfo.getMessage());
            if (authorizedInfo == TscSsipApiErrorCode.SUCCESS) {
                List<VersionVo> versionList = this.tscNaviApiService.getVersion();
                log.info("version list: {}", versionList.toString());
                result.setVersions(versionList);
            }
        }
        catch (Exception e) {
            log.error("getDeviceAuthInfo: {}", e.getMessage());
            // 데이터베이스 오류
            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        // 이력저장
        this.tscNaviApiService.insertInvokeHs(apiInvokeVo, true);
        log.info("Auth: {}, {}", deviceId, result.toString());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @PostMapping(value = {NAVI_DEVICE_REGISTER}, produces = {"application/json; charset=utf8"})
    public ResponseEntity<AbstractTscSsipApiResult> registerDevice(@RequestBody DeviceInfo deviceInfo,  HttpServletRequest request){
        final String apiId = NAVI_DEVICE_REGISTER;
        final String remoteIP = ApiUtils.getRemoteIP(request);
        log.info("{}, {}, {}", apiId, remoteIP, deviceInfo.toString());

        try {
            this.tscNaviApiService.registerDevice(deviceInfo);
        }
        catch(Exception e) {
            log.error("registerDevice: {}", e.getMessage().toString());
            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
            return new ResponseEntity<> (error, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        TscNaviApiResultDeviceRegisterInfo result = new TscNaviApiResultDeviceRegisterInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
        result.setResult("ok");
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @GetMapping(value = {NAVI_DOWNLOADS})
    public ResponseEntity<Resource> download(@PathVariable("fileName") String fileName, HttpServletRequest request) {
        final String apiId = NAVI_DOWNLOADS;
        final String remoteIP = ApiUtils.getRemoteIP(request);
        log.info("{}, {}, {}", apiId, remoteIP, fileName);

        try {
            String separator = System.getProperty("file.separator");
            String fileFullName = System.getProperty("user.dir")+separator+"download"+separator+fileName;
            Path path = Paths.get(fileFullName);
            File file2Upload = path.toFile();
            String contentType = "application/download";
            //String contentType = Files.probeContentType(path);
            Resource resource = new InputStreamResource(Files.newInputStream(path));
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_TYPE, contentType);
            headers.setContentLength(file2Upload.length());
            headers.setContentDisposition(ContentDisposition.parse("attachment;" + " filename=\"" + fileName + "\";"));

            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
        }
        catch (IOException e) {
            log.error("download: {}", e.toString());
            return new ResponseEntity<> (HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @GetMapping(value = {NAVI_API_UUID})
    public String getUUID(){
        String uid = UUID.randomUUID().toString();
        uid = uid.replace("-","").toUpperCase();
        return uid;
    }

}
