/*
 * Copyright (c) 2025 Rostock University Library
 * Licensed under the MIT License. See LICENSE file in the project root.
 */
package de.uni.rostock.ub.wsrb.edition.webapp.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import de.uni.rostock.ub.wsrb.edition.webapp.service.XSLTDocumentationService;
import de.uni.rostock.ub.wsrb.edition.webapp.service.XSLTTranskriptionService;
import de.uni.rostock.ub.wsrb.edition.webapp.util.WSRBUtil;

@Controller
public class DatenTEIController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DatenTEIController.class);

    private static final String LAST_RESTART = Instant.now().toString();

    @Autowired
    XSLTDocumentationService docsService;

    @Autowired
    XSLTTranskriptionService transkriptionService;

    @Value("${wsrb.transkription.ids}")
    private List<String> transkriptionList;

    @Value("${wsrb.edition.id}")
    private String editionId;

    @Value("${wsrb.dokumentation.id}")
    private String dokumentationId;

    @Value("${wsrb.folder.teixml}")
    private String teixmlFolder;

    @GetMapping(path = "/daten_tei")
    ModelAndView datenTei(@RequestParam(name = "id", defaultValue = "") String id) {
        ModelAndView mav = new ModelAndView("daten_tei");
        mav.addObject("lastRestart", LAST_RESTART);
        mav.addObject("pageLabels", docsService.getPageLabels());

        List<String> xmlSourceList = new ArrayList<>();
        xmlSourceList.add(editionId);
        xmlSourceList.addAll(transkriptionList);
        xmlSourceList.add(dokumentationId);

        mav.addObject("xmlSourceList", xmlSourceList);
        mav.addObject("currentXmlSource", id);

        if (id.isEmpty()) {
            //return introduction page
            mav.addObject("xmlSourceIntro", docsService.getHtmlBody().get("daten_tei__intro"));
        }
        return mav;
    }

    @GetMapping(path = "/xml_raw/{id}" + WSRBUtil.TEI_FILE_EXTENSION)
    public ResponseEntity<StreamingResponseBody> sendStreamingResponse(
        @PathVariable(name = "id") String id) {
        StreamingResponseBody responseBody = new StreamingResponseBody() {
            @Override
            public void writeTo(OutputStream out) throws IOException {
                String resourcePath = calcResourcePath(id);
                if (resourcePath == null) {
                    String s = "<!-- Not found: " + id + "-->";
                    InputStream stream = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
                    stream.transferTo(out);
                } else {
                    try (InputStream is = getClass().getResourceAsStream(resourcePath)) {
                        is.transferTo(out);
                    } catch (IOException e) {
                        LOGGER.error("Problem with raw TEI output", e);
                    }
                }
            }
        };
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + id + ".tei.xml")
            .body(responseBody);
    }

    @GetMapping(path = "/xml_encoded/{id}" + WSRBUtil.TEI_FILE_EXTENSION)
    public ResponseEntity<StreamingResponseBody> sendEncodedXML(
        @PathVariable(name = "id") String id) {
        StreamingResponseBody responseBody = new StreamingResponseBody() {
            @Override
            public void writeTo(OutputStream out) throws IOException {
                String resourcePath = calcResourcePath(id);
                if (resourcePath == null) {
                    String s = "<!-- Not found: " + id + "-->";
                    InputStream stream = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
                    stream.transferTo(out);
                } else {
                    try (InputStream in = getClass().getResourceAsStream(resourcePath);
                        Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
                        Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
                        int ch;
                        while ((ch = reader.read()) != -1) {
                            char currentChar = (char) ch;
                            writer.write(switch (currentChar) {
                                case '<' -> "&lt;";
                                case '>' -> "&gt;";
                                case '&' -> "&amp;";
                                case '"' -> "&quot;";
                                case '\'' -> "&apos;";
                                default -> String.valueOf(currentChar);
                            });
                        }
                    } catch (IOException e) {
                        LOGGER.error("Problem with raw TEI output", e);
                    }
                }
            }
        };
        return ResponseEntity.ok()
            .body(responseBody);
    }

    private String calcResourcePath(String id) {
        if (editionId.equals(id)) {
            return teixmlFolder + "edition/" + id + WSRBUtil.TEI_FILE_EXTENSION;
        } else if (transkriptionList.contains(id)) {
            return teixmlFolder + "transkriptionen/" + id + WSRBUtil.TEI_FILE_EXTENSION;
        } else if (dokumentationId.equals(id)) {
            return teixmlFolder + "dokumentation/" + id + WSRBUtil.TEI_FILE_EXTENSION;
        }
        return null;
    }
}
