package com.cameleer.server.app.alerting.controller;

import com.cameleer.server.app.alerting.dto.AlertDto;
import com.cameleer.server.app.alerting.dto.BulkReadRequest;
import com.cameleer.server.app.alerting.dto.UnreadCountResponse;
import com.cameleer.server.app.alerting.notify.InAppInboxQuery;
import com.cameleer.server.app.web.EnvPath;
import com.cameleer.server.core.alerting.AlertInstance;
import com.cameleer.server.core.alerting.AlertInstanceRepository;
import com.cameleer.server.core.alerting.AlertReadRepository;
import com.cameleer.server.core.alerting.AlertSeverity;
import com.cameleer.server.core.alerting.AlertState;
import com.cameleer.server.core.runtime.Environment;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

import java.time.Instant;
import java.util.List;
import java.util.UUID;

/**
 * REST controller for the in-app alert inbox (env-scoped).
 * VIEWER+ can read their own inbox; OPERATOR+ can ack any alert.
 */
@RestController
@RequestMapping("/api/v1/environments/{envSlug}/alerts")
@Tag(name = "Alerts Inbox", description = "In-app alert inbox, ack and read tracking (env-scoped)")
@PreAuthorize("hasAnyRole('VIEWER','OPERATOR','ADMIN')")
public class AlertController {

    private static final int DEFAULT_LIMIT = 50;

    private final InAppInboxQuery inboxQuery;
    private final AlertInstanceRepository instanceRepo;
    private final AlertReadRepository readRepo;

    public AlertController(InAppInboxQuery inboxQuery,
                           AlertInstanceRepository instanceRepo,
                           AlertReadRepository readRepo) {
        this.inboxQuery = inboxQuery;
        this.instanceRepo = instanceRepo;
        this.readRepo = readRepo;
    }

    @GetMapping
    public List<AlertDto> list(
            @EnvPath Environment env,
            @RequestParam(defaultValue = "50") int limit,
            @RequestParam(required = false) List<AlertState> state,
            @RequestParam(required = false) List<AlertSeverity> severity) {
        String userId = currentUserId();
        int effectiveLimit = Math.min(limit, 200);
        return inboxQuery.listInbox(env.id(), userId, state, severity, effectiveLimit)
                .stream().map(AlertDto::from).toList();
    }

    @GetMapping("/unread-count")
    public UnreadCountResponse unreadCount(@EnvPath Environment env) {
        return inboxQuery.countUnread(env.id(), currentUserId());
    }

    @GetMapping("/{id}")
    public AlertDto get(@EnvPath Environment env, @PathVariable UUID id) {
        AlertInstance instance = requireInstance(id, env.id());
        return AlertDto.from(instance);
    }

    @PostMapping("/{id}/ack")
    public AlertDto ack(@EnvPath Environment env, @PathVariable UUID id) {
        AlertInstance instance = requireInstance(id, env.id());
        String userId = currentUserId();
        instanceRepo.ack(id, userId, Instant.now());
        // Re-fetch to return fresh state
        return AlertDto.from(instanceRepo.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)));
    }

    @PostMapping("/{id}/read")
    public void read(@EnvPath Environment env, @PathVariable UUID id) {
        requireInstance(id, env.id());
        String userId = currentUserId();
        readRepo.markRead(userId, id);
    }

    @PostMapping("/bulk-read")
    public void bulkRead(@EnvPath Environment env,
                         @Valid @RequestBody BulkReadRequest req) {
        String userId = currentUserId();
        // filter to only instances in this env
        List<UUID> filtered = req.instanceIds().stream()
                .filter(instanceId -> instanceRepo.findById(instanceId)
                        .map(i -> i.environmentId().equals(env.id()))
                        .orElse(false))
                .toList();
        if (!filtered.isEmpty()) {
            readRepo.bulkMarkRead(userId, filtered);
        }
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    private AlertInstance requireInstance(UUID id, UUID envId) {
        AlertInstance instance = instanceRepo.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Alert not found: " + id));
        if (!instance.environmentId().equals(envId)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND,
                    "Alert not found in this environment: " + id);
        }
        return instance;
    }

    private String currentUserId() {
        var auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || auth.getName() == null) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "No authentication");
        }
        String name = auth.getName();
        return name.startsWith("user:") ? name.substring(5) : name;
    }
}
