package com.walkguide.service;

import com.walkguide.dto.request.SosRequest;
import com.walkguide.dto.response.SosEventResponse;
import com.walkguide.entity.SosEvent;
import com.walkguide.entity.User;
import com.walkguide.enums.ActivityLogType;
import com.walkguide.enums.PairingStatus;
import com.walkguide.enums.SosStatus;
import com.walkguide.exception.ResourceNotFoundException;
import com.walkguide.repository.*;
import com.walkguide.websocket.LocationBroadcaster;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class SosService {

    private final SosEventRepository sosEventRepository;
    private final PairingRelationRepository pairingRelationRepository;
    private final UserRepository userRepository;
    private final ActivityLogService activityLogService;
    private final FcmService fcmService;

    // ✅ BARU: WebSocket broadcast untuk SOS real-time ke Guardian
    private final LocationBroadcaster locationBroadcaster;

    @Transactional
    public SosEventResponse triggerSos(Long userId, SosRequest req) {
        SosEvent sos = SosEvent.builder()
                .userId(userId)
                .triggerType(req.getTriggerType() != null ? req.getTriggerType() : "MANUAL")
                .lat(req.getLat())
                .lng(req.getLng())
                .status(SosStatus.TRIGGERED)
                .build();
        sos = sosEventRepository.save(sos);
        final SosEvent savedSos = sos;

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User tidak ditemukan"));

        activityLogService.createLog(user, ActivityLogType.SOS_TRIGGERED,
                "SOS dikirim via " + sos.getTriggerType(), null);

        SosEventResponse sosResponse = toResponse(savedSos);

        // Kirim ke Guardian via FCM (background) + WebSocket (foreground)
        pairingRelationRepository.findByUser_IdAndStatus(userId, PairingStatus.ACTIVE)
                .ifPresent(pairing -> {
                    User guardian = pairing.getGuardian();
                    String guardianFcm = guardian.getFcmToken();
                    String locStr = req.getLat() != null
                            ? String.format("Lat:%.4f,Lng:%.4f", req.getLat(), req.getLng())
                            : "Lokasi tidak tersedia";

                    // FCM untuk background/killed app
                    fcmService.sendHighPriority(guardianFcm,
                            "🚨 SOS ALERT dari " + user.getDisplayName(),
                            user.getDisplayName() + " butuh bantuan! " + locStr,
                            Map.of("type",   "SOS_ALERT",
                                   "sosId",  String.valueOf(savedSos.getId()),
                                   "userId", String.valueOf(userId),
                                   "lat",    String.valueOf(req.getLat() != null ? req.getLat() : 0),
                                   "lng",    String.valueOf(req.getLng() != null ? req.getLng() : 0)));

                    // ✅ WebSocket untuk foreground real-time — Guardian subscribe /queue/sos/{guardianId}
                    locationBroadcaster.broadcastSos(guardian.getId(), sosResponse);

                    log.info("[SOS] Alert sent to Guardian={} for User={} | trigger={}",
                            guardian.getId(), userId, savedSos.getTriggerType());
                });

        return sosResponse;
    }

    @Transactional
    public SosEventResponse acknowledgeSos(Long guardianId, Long sosId) {
        SosEvent sos = sosEventRepository.findById(sosId)
                .orElseThrow(() -> new ResourceNotFoundException("SOS event tidak ditemukan"));

        sos.setStatus(SosStatus.ACKNOWLEDGED);
        sos.setAcknowledgedAt(LocalDateTime.now());
        sosEventRepository.save(sos);

        activityLogService.createLog(
                userRepository.findById(sos.getUserId())
                        .orElseThrow(() -> new ResourceNotFoundException("User tidak ditemukan")),
                ActivityLogType.SOS_ACKNOWLEDGED,
                "Guardian mengakui SOS", null);

        // Beritahu user
        pairingRelationRepository.findByUser_IdAndStatus(sos.getUserId(), PairingStatus.ACTIVE)
                .ifPresent(pairing -> {
                    String userFcm = pairing.getUser().getFcmToken();
                    fcmService.sendToToken(userFcm,
                            "Guardian Merespons SOS",
                            "Guardian kamu sudah melihat SOS kamu dan sedang menuju lokasimu",
                            Map.of("type", "SOS_ACKNOWLEDGED"));
                });

        return toResponse(sos);
    }

    public Page<SosEventResponse> getSosEvents(Long userId, Pageable pageable) {
        return sosEventRepository.findByUserIdOrderByCreatedAtDesc(userId, pageable)
                .map(this::toResponse);
    }

    public Page<SosEventResponse> getSosEventsForGuardian(Long guardianId, Pageable pageable) {
        var pairing = pairingRelationRepository
                .findByGuardian_IdAndStatus(guardianId, PairingStatus.ACTIVE)
                .orElseThrow(() -> new ResourceNotFoundException("Tidak ada user yang dipair"));
        return sosEventRepository
                .findByUserIdOrderByCreatedAtDesc(pairing.getUser().getId(), pageable)
                .map(this::toResponse);
    }

    private SosEventResponse toResponse(SosEvent s) {
        return SosEventResponse.builder()
                .id(s.getId())
                .userId(s.getUserId())
                .triggerType(s.getTriggerType())
                .lat(s.getLat()).lng(s.getLng())
                .status(s.getStatus().name())
                .acknowledgedAt(s.getAcknowledgedAt())
                .createdAt(s.getCreatedAt())
                .build();
    }
}
