package com.petshop.backend.controller;

import com.petshop.backend.config.WebSocketAuthChannelInterceptor;
import com.petshop.backend.dto.chat.MessageRequest;
import com.petshop.backend.dto.chat.MessageResponse;
import com.petshop.backend.entity.User;
import com.petshop.backend.repository.UserRepository;
import com.petshop.backend.security.AppPrincipal;
import com.petshop.backend.security.JwtUtil;
import com.petshop.backend.service.ChatRealtimeService;
import com.petshop.backend.service.ChatService;
import com.petshop.backend.service.OpenRouterAiService;
import jakarta.validation.Valid;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;

import java.security.Principal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Controller
public class ChatWebSocketController {

    private final ChatService chatService;
    private final OpenRouterAiService openRouterAiService;
    private final ChatRealtimeService chatRealtimeService;
    private final UserRepository userRepository;
    private final JwtUtil jwtUtil;
    private final WebSocketAuthChannelInterceptor webSocketAuthChannelInterceptor;

    public ChatWebSocketController(
            ChatService chatService,
            ChatRealtimeService chatRealtimeService,
            UserRepository userRepository,
            JwtUtil jwtUtil,
            WebSocketAuthChannelInterceptor webSocketAuthChannelInterceptor,
            OpenRouterAiService openRouterAiService
    ) {
        this.openRouterAiService = openRouterAiService;
        this.chatService = chatService;
        this.chatRealtimeService = chatRealtimeService;
        this.userRepository = userRepository;
        this.jwtUtil = jwtUtil;
        this.webSocketAuthChannelInterceptor = webSocketAuthChannelInterceptor;
    }

    @MessageMapping("/chat/conversations/{id}/messages")
    @SendToUser("/queue/chat/errors")
    public void sendMessage(@DestinationVariable Long id, @Valid @Payload MessageRequest request, SimpMessageHeaderAccessor headerAccessor) {
        User user = resolveUser(headerAccessor);
        MessageResponse message = chatService.sendMessage(id, user.getId(), user.getRole(), request);
        chatRealtimeService.publishMessage(id, message);
        chatRealtimeService.publishConversationUpdate(id);
        openRouterAiService.generateAndSendReply(id, message.getId());
    }

    @MessageExceptionHandler({IllegalArgumentException.class, RuntimeException.class})
    @SendToUser("/queue/chat/errors")
    public Map<String, Object> handleMessageException(Exception ex, SimpMessageHeaderAccessor headerAccessor) {
        return webSocketAuthChannelInterceptor.buildErrorPayload(ex, headerAccessor.getDestination(), headerAccessor.getUser());
    }

    private User resolveUser(SimpMessageHeaderAccessor headerAccessor) {
        Principal principal = headerAccessor.getUser();
        if (principal instanceof org.springframework.security.authentication.UsernamePasswordAuthenticationToken authenticationToken
                && authenticationToken.getPrincipal() instanceof AppPrincipal appPrincipal) {
            return userRepository.findById(appPrincipal.getUserId())
                    .orElseThrow(() -> new IllegalArgumentException("User not found"));
        }

        if (principal instanceof AppPrincipal appPrincipal) {
            return userRepository.findById(appPrincipal.getUserId())
                    .orElseThrow(() -> new IllegalArgumentException("User not found"));
        }

        String tokenHeader = firstHeader(headerAccessor, "Authorization");
        if (tokenHeader == null || tokenHeader.isBlank()) {
            tokenHeader = firstHeader(headerAccessor, "token");
        }
        if (tokenHeader == null || tokenHeader.isBlank()) {
            throw new IllegalArgumentException("User not authenticated");
        }

        String token = extractToken(tokenHeader);
        Long userId;
        try {
            userId = jwtUtil.extractUserId(token);
        } catch (RuntimeException ex) {
            throw new IllegalArgumentException("Invalid websocket token", ex);
        }
        User user = userId == null ? null : userRepository.findById(userId).orElse(null);
        if (user == null) {
            throw new IllegalArgumentException("User not found");
        }
        if (user.getActive() == null || !user.getActive()) {
            throw new IllegalArgumentException("User account is inactive");
        }
        if (!jwtUtil.validateToken(token, user)) {
            throw new IllegalArgumentException("Invalid websocket token");
        }
        return user;
    }

    private String firstHeader(SimpMessageHeaderAccessor headerAccessor, String name) {
        List<String> values = headerAccessor.getNativeHeader(name);
        if (values != null && !values.isEmpty()) {
            return values.get(0);
        }
        Map<String, List<String>> headers = headerAccessor.toNativeHeaderMap();
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            if (entry.getKey().equalsIgnoreCase(name)) {
                return entry.getValue() == null || entry.getValue().isEmpty() ? null : entry.getValue().get(0);
            }
        }
        return null;
    }

    private String extractToken(String rawValue) {
        String normalized = rawValue.trim();
        return normalized.regionMatches(true, 0, "Bearer ", 0, 7) ? normalized.substring(7) : normalized;
    }
}
