package com.honey.honey.controller;

import com.honey.honey.dto.*;
import com.honey.honey.model.Admin;
import com.honey.honey.model.SupportMessage;
import com.honey.honey.model.SupportTicket;
import com.honey.honey.model.UserA;
import com.honey.honey.repository.AdminRepository;
import com.honey.honey.repository.SupportMessageRepository;
import com.honey.honey.repository.SupportTicketRepository;
import com.honey.honey.repository.UserARepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import jakarta.persistence.criteria.Predicate;
import jakarta.validation.Valid;

import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/admin/tickets")
@RequiredArgsConstructor
@PreAuthorize("hasAnyRole('ADMIN')")
public class AdminSupportTicketController {

    private final SupportTicketRepository supportTicketRepository;
    private final SupportMessageRepository supportMessageRepository;
    private final UserARepository userARepository;
    private final AdminRepository adminRepository;

    @GetMapping
    public ResponseEntity<Map<String, Object>> getTickets(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "50") int size,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) Integer userId,
            @RequestParam(required = false) String search) {

        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());

        // Build specification
        Specification<SupportTicket> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (status != null && !status.trim().isEmpty()) {
                try {
                    SupportTicket.TicketStatus ticketStatus = SupportTicket.TicketStatus.valueOf(status.toUpperCase());
                    predicates.add(cb.equal(root.get("status"), ticketStatus));
                } catch (IllegalArgumentException e) {
                    // Invalid status, ignore
                }
            }

            if (userId != null) {
                predicates.add(cb.equal(root.get("user").get("id"), userId));
            }

            if (search != null && !search.trim().isEmpty()) {
                String searchPattern = "%" + search.trim() + "%";
                predicates.add(cb.or(
                    cb.like(cb.lower(root.get("subject")), searchPattern.toLowerCase())
                ));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        Page<SupportTicket> ticketPage = supportTicketRepository.findAll(spec, pageable);

        // Fetch user names and message counts
        List<Integer> userIds = ticketPage.getContent().stream()
                .map(t -> t.getUser().getId())
                .distinct()
                .collect(Collectors.toList());

        Map<Integer, String> userNameMap = userARepository.findAllById(userIds).stream()
                .collect(Collectors.toMap(
                        UserA::getId,
                        u -> u.getTelegramName() != null && !u.getTelegramName().equals("-")
                                ? u.getTelegramName()
                                : u.getScreenName()
                ));

        // Convert to DTOs
        Page<AdminSupportTicketDto> dtoPage = ticketPage.map(ticket -> {
            String userName = userNameMap.getOrDefault(ticket.getUser().getId(), "Unknown");
            long messageCount = supportMessageRepository.countByTicketId(ticket.getId());
            
            // Get last message preview
            List<SupportMessage> lastMessages = supportMessageRepository.findByTicketIdOrderByCreatedAtAsc(ticket.getId());
            String lastMessagePreview = "";
            Instant lastMessageAt = null;
            if (!lastMessages.isEmpty()) {
                SupportMessage lastMsg = lastMessages.get(lastMessages.size() - 1);
                lastMessagePreview = lastMsg.getMessage().length() > 100 
                        ? lastMsg.getMessage().substring(0, 100) + "..."
                        : lastMsg.getMessage();
                lastMessageAt = lastMsg.getCreatedAt();
            }

            return AdminSupportTicketDto.builder()
                    .id(ticket.getId())
                    .userId(ticket.getUser().getId())
                    .userName(userName)
                    .subject(ticket.getSubject())
                    .status(ticket.getStatus().name())
                    .createdAt(ticket.getCreatedAt())
                    .updatedAt(ticket.getUpdatedAt())
                    .messageCount(messageCount)
                    .lastMessagePreview(lastMessagePreview)
                    .lastMessageAt(lastMessageAt)
                    .build();
        });

        Map<String, Object> response = new HashMap<>();
        response.put("content", dtoPage.getContent());
        response.put("totalElements", dtoPage.getTotalElements());
        response.put("totalPages", dtoPage.getTotalPages());
        response.put("currentPage", dtoPage.getNumber());
        response.put("size", dtoPage.getSize());
        response.put("hasNext", dtoPage.hasNext());
        response.put("hasPrevious", dtoPage.hasPrevious());

        return ResponseEntity.ok(response);
    }

    @GetMapping("/{id}")
    public ResponseEntity<AdminSupportTicketDetailDto> getTicketDetail(@PathVariable Long id) {
        return supportTicketRepository.findById(id)
                .map(ticket -> {
                    String userName = ticket.getUser().getTelegramName() != null && !ticket.getUser().getTelegramName().equals("-")
                            ? ticket.getUser().getTelegramName()
                            : ticket.getUser().getScreenName();

                    List<SupportMessage> messages = supportMessageRepository.findByTicketIdOrderByCreatedAtAsc(id);
                    
                    // Get all admin user IDs from admins table
                    List<Integer> adminUserIds = adminRepository.findAll().stream()
                            .filter(admin -> admin.getUserId() != null)
                            .map(Admin::getUserId)
                            .collect(Collectors.toList());
                    
                    List<AdminSupportMessageDto> messageDtos = messages.stream()
                            .map(msg -> {
                                // Check if message is from admin by checking if user_id is in admins table
                                boolean isAdmin = adminUserIds.contains(msg.getUser().getId());
                                String msgUserName = msg.getUser().getTelegramName() != null && !msg.getUser().getTelegramName().equals("-")
                                        ? msg.getUser().getTelegramName()
                                        : msg.getUser().getScreenName();
                                
                                return AdminSupportMessageDto.builder()
                                        .id(msg.getId())
                                        .userId(msg.getUser().getId())
                                        .userName(msgUserName)
                                        .message(msg.getMessage())
                                        .createdAt(msg.getCreatedAt())
                                        .isAdmin(isAdmin)
                                        .build();
                            })
                            .collect(Collectors.toList());

                    return AdminSupportTicketDetailDto.builder()
                            .id(ticket.getId())
                            .userId(ticket.getUser().getId())
                            .userName(userName)
                            .subject(ticket.getSubject())
                            .status(ticket.getStatus().name())
                            .createdAt(ticket.getCreatedAt())
                            .updatedAt(ticket.getUpdatedAt())
                            .messages(messageDtos)
                            .build();
                })
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping("/{id}/reply")
    public ResponseEntity<?> replyToTicket(
            @PathVariable Long id,
            @Valid @RequestBody SupportTicketReplyRequest request) {
        
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String adminUsername;
        
        if (authentication.getPrincipal() instanceof UserDetails) {
            adminUsername = ((UserDetails) authentication.getPrincipal()).getUsername();
        } else {
            // Fallback if principal is a String
            adminUsername = authentication.getName();
        }
        
        // Get admin entity to find user_id
        Admin admin = adminRepository.findByUsername(adminUsername)
                .orElseThrow(() -> new RuntimeException("Admin not found: " + adminUsername));
        
        if (admin.getUserId() == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "Admin account is not linked to a user account"));
        }
        
        // Get the admin's UserA entity
        UserA adminUser = userARepository.findById(admin.getUserId())
                .orElseThrow(() -> new RuntimeException("Admin user account not found: " + admin.getUserId()));
        
        return supportTicketRepository.findById(id)
                .map(ticket -> {
                    // Create message without prefix, using admin's user_id
                    SupportMessage message = SupportMessage.builder()
                            .ticket(ticket)
                            .user(adminUser) // Use admin's UserA entity
                            .message(request.getMessage()) // Save message as-is, no prefix
                            .build();
                    
                    supportMessageRepository.save(message);
                    
                    // Update ticket updated_at
                    ticket.setUpdatedAt(java.time.Instant.now());
                    if (ticket.getStatus() == SupportTicket.TicketStatus.CLOSED) {
                        ticket.setStatus(SupportTicket.TicketStatus.OPENED); // Reopen if admin replies
                    }
                    supportTicketRepository.save(ticket);
                    
                    return ResponseEntity.ok(Map.of("message", "Reply sent successfully"));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping("/{id}/close")
    public ResponseEntity<?> closeTicket(@PathVariable Long id) {
        return supportTicketRepository.findById(id)
                .map(ticket -> {
                    ticket.setStatus(SupportTicket.TicketStatus.CLOSED);
                    ticket.setUpdatedAt(java.time.Instant.now());
                    supportTicketRepository.save(ticket);
                    return ResponseEntity.ok(Map.of("message", "Ticket closed"));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping("/{id}/reopen")
    public ResponseEntity<?> reopenTicket(@PathVariable Long id) {
        return supportTicketRepository.findById(id)
                .map(ticket -> {
                    ticket.setStatus(SupportTicket.TicketStatus.OPENED);
                    ticket.setUpdatedAt(java.time.Instant.now());
                    supportTicketRepository.save(ticket);
                    return ResponseEntity.ok(Map.of("message", "Ticket reopened"));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @PutMapping("/messages/{messageId}")
    public ResponseEntity<?> editMessage(
            @PathVariable Long messageId,
            @Valid @RequestBody SupportTicketReplyRequest request) {
        
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String adminUsername;
        
        if (authentication.getPrincipal() instanceof UserDetails) {
            adminUsername = ((UserDetails) authentication.getPrincipal()).getUsername();
        } else {
            adminUsername = authentication.getName();
        }
        
        // Get admin entity to find user_id
        Admin admin = adminRepository.findByUsername(adminUsername)
                .orElseThrow(() -> new RuntimeException("Admin not found: " + adminUsername));
        
        if (admin.getUserId() == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "Admin account is not linked to a user account"));
        }
        
        return supportMessageRepository.findById(messageId)
                .map(message -> {
                    // Check if message is from this admin
                    if (!message.getUser().getId().equals(admin.getUserId())) {
                        return ResponseEntity.badRequest().body(Map.of("error", "You can only edit your own messages"));
                    }
                    
                    // Check if user is an admin (verify in admins table)
                    boolean isAdmin = adminRepository.findAll().stream()
                            .anyMatch(a -> a.getUserId() != null && a.getUserId().equals(message.getUser().getId()));
                    
                    if (!isAdmin) {
                        return ResponseEntity.badRequest().body(Map.of("error", "Only admin messages can be edited"));
                    }
                    
                    // Update message
                    message.setMessage(request.getMessage());
                    supportMessageRepository.save(message);
                    
                    // Update ticket updated_at
                    message.getTicket().setUpdatedAt(java.time.Instant.now());
                    supportTicketRepository.save(message.getTicket());
                    
                    return ResponseEntity.ok(Map.of("message", "Message updated successfully"));
                })
                .orElse(ResponseEntity.notFound().build());
    }
}

