package com.pandoli365.bibimbap.controller;

import com.pandoli365.bibimbap.data.UnityFeedSourceData;
import com.pandoli365.bibimbap.mapper.UnityFeedItemsMapper;
import com.pandoli365.bibimbap.mapper.UnityFeedSourcesMapper;
import com.pandoli365.bibimbap.security.CsrfTokens;
import com.pandoli365.bibimbap.security.SsrfSafeFetcher;
import com.pandoli365.bibimbap.service.UnityFeedPoller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Controller
public class UnityFeedAdminController {

    private final UnityFeedSourcesMapper sourcesMapper;
    private final UnityFeedItemsMapper itemsMapper;
    private final SsrfSafeFetcher ssrfSafeFetcher;
    private final UnityFeedPoller unityFeedPoller;

    public UnityFeedAdminController(
            UnityFeedSourcesMapper sourcesMapper,
            UnityFeedItemsMapper itemsMapper,
            SsrfSafeFetcher ssrfSafeFetcher,
            UnityFeedPoller unityFeedPoller
    ) {
        this.sourcesMapper = sourcesMapper;
        this.itemsMapper = itemsMapper;
        this.ssrfSafeFetcher = ssrfSafeFetcher;
        this.unityFeedPoller = unityFeedPoller;
    }

    @GetMapping("/admin/unity-feeds")
    public String unityFeedsPage(HttpServletRequest request, Model model) {
        model.addAttribute("sources", sourcesMapper.listAll());
        model.addAttribute("unackItems", itemsMapper.listUnacknowledged(50));
        model.addAttribute("unackCount", itemsMapper.countUnacknowledged());
        model.addAttribute("csrfToken", CsrfTokens.getOrCreate(request.getSession()));
        return "admin-unity-feeds";
    }

    @PostMapping("/admin/unity-feeds")
    @Transactional
    public ResponseEntity<Map<String, Object>> createSource(
            @RequestParam(name = "name", required = false) String name,
            @RequestParam(name = "feedUrl", required = false) String feedUrl,
            HttpServletRequest request
    ) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        String normalizedName = trimToNull(name);
        String normalizedUrl = trimToNull(feedUrl);
        if (normalizedName == null || normalizedName.length() > 120) {
            return response(HttpStatus.BAD_REQUEST, "피드 이름을 120자 이내로 입력해 주세요.");
        }
        if (normalizedUrl == null || normalizedUrl.length() > 2048) {
            return response(HttpStatus.BAD_REQUEST, "피드 URL 을 2048자 이내로 입력해 주세요.");
        }

        URI uri;
        try {
            uri = new URI(normalizedUrl);
        } catch (URISyntaxException e) {
            return response(HttpStatus.BAD_REQUEST, "피드 URL 이 안전하지 않거나 접근 불가합니다.");
        }
        if (!ssrfSafeFetcher.isFetchableUrl(uri)) {
            return response(HttpStatus.BAD_REQUEST, "피드 URL 이 안전하지 않거나 접근 불가합니다.");
        }

        UnityFeedSourceData source = new UnityFeedSourceData();
        source.setName(normalizedName);
        source.setFeedUrl(normalizedUrl);

        try {
            sourcesMapper.insert(source);
        } catch (DuplicateKeyException e) {
            return response(HttpStatus.CONFLICT, "이미 등록된 피드 URL 입니다.");
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", 200);
        body.put("message", "피드 소스를 등록했습니다.");
        body.put("sourceId", source.getId());
        return ResponseEntity.ok(body);
    }

    @PostMapping("/admin/unity-feeds/{id}/toggle")
    @Transactional
    public ResponseEntity<Map<String, Object>> toggleSource(
            @PathVariable("id") long id,
            HttpServletRequest request
    ) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        UnityFeedSourceData existing = sourcesMapper.getById(id);
        if (existing == null) {
            return response(HttpStatus.NOT_FOUND, "피드 소스를 찾을 수 없습니다.");
        }

        sourcesMapper.toggle(id);
        UnityFeedSourceData updated = sourcesMapper.getById(id);

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", 200);
        body.put("message", "피드 소스 상태를 변경했습니다.");
        body.put("isActive", updated == null ? null : updated.getIsActive());
        return ResponseEntity.ok(body);
    }

    @PostMapping("/admin/unity-feeds/{id}/delete")
    @Transactional
    public ResponseEntity<Map<String, Object>> deleteSource(
            @PathVariable("id") long id,
            HttpServletRequest request
    ) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        UnityFeedSourceData existing = sourcesMapper.getById(id);
        if (existing == null) {
            return response(HttpStatus.NOT_FOUND, "피드 소스를 찾을 수 없습니다.");
        }

        sourcesMapper.delete(id);
        return response(HttpStatus.OK, "피드 소스를 삭제했습니다.");
    }

    @PostMapping("/admin/unity-feeds/items/{itemId}/ack")
    @Transactional
    public ResponseEntity<Map<String, Object>> acknowledgeItem(
            @PathVariable("itemId") long itemId,
            HttpServletRequest request
    ) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        itemsMapper.acknowledge(itemId);
        return response(HttpStatus.OK, "확인 처리했습니다.");
    }

    @PostMapping("/admin/unity-feeds/poll")
    public ResponseEntity<Map<String, Object>> pollNow(HttpServletRequest request) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        int newCount = 0;
        List<UnityFeedSourceData> sources = sourcesMapper.listAll();
        if (sources != null) {
            for (UnityFeedSourceData source : sources) {
                if (source == null || source.getId() == null) {
                    continue;
                }
                if (!Boolean.TRUE.equals(source.getIsActive())) {
                    continue;
                }
                newCount += unityFeedPoller.pollOnce(source.getId());
            }
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", 200);
        body.put("message", "폴링을 완료했습니다.");
        body.put("newCount", newCount);
        return ResponseEntity.ok(body);
    }

    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String text = value.trim();
        return text.isBlank() ? null : text;
    }

    private ResponseEntity<Map<String, Object>> response(HttpStatus status, String message) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", status.value());
        body.put("message", message);
        return ResponseEntity.status(status).body(body);
    }
}
