package cd.casic.server.system.plugin.example.web;

import cd.casic.plugin.BufferedPluginBundleResource;
import cd.casic.plugin.FrontResourceProcessor;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URI;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

@RestController
public class FrontResourceController {

    @Resource
    BufferedPluginBundleResource bufferedPluginBundleResource;

    @Resource
    FrontResourceProcessor frontResourceProcessor;

    private static final CacheControl MAX_CACHE_CONTROL = CacheControl.maxAge(365, TimeUnit.DAYS);

    @GetMapping("/plugins/-/bundle.js")
    public ResponseEntity<?> fetchJsBundle(HttpServletRequest request,
                                           @RequestParam(required = false) String v) throws IOException {
        if (v != null) {
            FileSystemResource fsRes = bufferedPluginBundleResource.getJsBundle(v, frontResourceProcessor.uglifyJsBundle());

            Instant lastModified = Instant.ofEpochMilli(fsRes.lastModified());
            if (isModified(request, lastModified)) {
                HttpHeaders headers = new HttpHeaders();
                headers.setCacheControl(MAX_CACHE_CONTROL);
                headers.setContentType(MediaType.parseMediaType("application/x-javascript"));
                headers.setLastModified(lastModified.toEpochMilli());

                return ResponseEntity.ok()
                        .headers(headers)
                        .body(new InputStreamResource(fsRes.getInputStream()));
            } else {
                return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
            }
        } else {
            String newVersion = frontResourceProcessor.generateJsBundleVersion();
            String redirectUrl = buildJsBundleUri("js", newVersion).toString();

            return ResponseEntity.status(HttpStatus.TEMPORARY_REDIRECT)
                    .header(HttpHeaders.LOCATION, redirectUrl)
                    .build();
        }
    }

    @GetMapping("/plugins/-/bundle.css")
    public ResponseEntity<?> fetchCssBundle(HttpServletRequest request,
                                           @RequestParam(required = false) String v) throws IOException {
        if (v != null) {
            FileSystemResource fsRes = bufferedPluginBundleResource.getCssBundle(v, frontResourceProcessor.uglifyCssBundle());

            Instant lastModified = Instant.ofEpochMilli(fsRes.lastModified());
            if (isModified(request, lastModified)) {
                HttpHeaders headers = new HttpHeaders();
                headers.setCacheControl(MAX_CACHE_CONTROL);
                headers.setContentType(MediaType.parseMediaType("text/css"));
                headers.setLastModified(lastModified.toEpochMilli());

                return ResponseEntity.ok()
                        .headers(headers)
                        .body(new InputStreamResource(fsRes.getInputStream()));
            } else {
                return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
            }
        } else {
            String newVersion = frontResourceProcessor.generateJsBundleVersion();
            String redirectUrl = buildJsBundleUri("css", newVersion).toString();

            return ResponseEntity.status(HttpStatus.TEMPORARY_REDIRECT)
                    .header(HttpHeaders.LOCATION, redirectUrl)
                    .build();
        }
    }
    private boolean isModified(HttpServletRequest request, Instant lastModified) {
        long ifModifiedSince = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
        return ifModifiedSince <= 0 || !lastModified.isBefore(Instant.ofEpochMilli(ifModifiedSince));
    }

    private URI buildJsBundleUri(String type, String version) {
        return URI.create(
                "/plugins/-/bundle." + type + "?v=" + version);
    }

}
