package com.rit.ems.controller;

import com.rit.ems.model.Event;
import com.rit.ems.model.Registration;
import com.rit.ems.repository.EventRepository;
import com.rit.ems.repository.RegistrationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/registrations")
public class RegistrationController {

    @Autowired
    private RegistrationRepository registrationRepository;

    @Autowired
    private EventRepository eventRepository;

    @GetMapping
    public List<Registration> getRegistrations(@RequestParam(required = false) Long userId,
                                               @RequestParam(required = false) Long eventId,
                                               @RequestParam(required = false) String teamCode) {
        List<Registration> list;
        if (userId != null) {
            list = registrationRepository.findByUserId(userId);
        } else if (eventId != null) {
            list = registrationRepository.findByEventId(eventId);
        } else if (teamCode != null) {
            list = registrationRepository.findByTeamCode(teamCode);
        } else {
            list = registrationRepository.findAll();
        }

        for (Registration reg : list) {
            if (reg.getRegisteredAt() != null) {
                String ra = reg.getRegisteredAt().replace(" ", "T");
                if (!ra.endsWith("Z")) ra += "Z";
                reg.setRegisteredAt(ra);
            }
        }
        return list;
    }

    @PostMapping
    public ResponseEntity<?> createRegistration(@RequestBody Registration payload) {
        Long userId = payload.getUserId();
        Long eventId = payload.getEventId();

        if (userId == null || eventId == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "userId and eventId are required"));
        }

        String regId = userId + "_" + eventId;
        Optional<Registration> existing = registrationRepository.findById(regId);
        if (existing.isPresent()) {
            return ResponseEntity.badRequest().body(Map.of("message", "You are already registered for this event."));
        }

        Optional<Event> eventOpt = eventRepository.findById(eventId);
        if (eventOpt.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", "Event not found"));
        }
        Event event = eventOpt.get();

        if (event.getEndDate() != null) {
            // Check deadline
            Instant deadline = parseDate(event.getEndDate());
            if (Instant.now().isAfter(deadline)) {
                return ResponseEntity.badRequest().body(Map.of("message", "Registration Blocked: The deadline for this event has passed."));
            }
        }

        List<Registration> eventRegs = registrationRepository.findByEventId(eventId);
        int currentParticipants = eventRegs.size();

        if (event.getMaxParticipants() != null && currentParticipants >= event.getMaxParticipants()) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: The event has reached its capacity."));
        }

        String studentDept = payload.getDept() != null ? payload.getDept() : (payload.getDepartment() != null ? payload.getDepartment() : "CSE");
        String studentSec = payload.getSection() != null ? payload.getSection() : "A";

        if (event.getDeptLimits() != null && !event.getDeptLimits().isEmpty()) {
            if (!event.getDeptLimits().containsKey(studentDept)) {
                return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: Department " + studentDept + " is not permitted to register."));
            }

            int deptLimit = Integer.parseInt(event.getDeptLimits().get(studentDept).toString());
            long deptRegsCount = eventRegs.stream().filter(r -> studentDept.equals(r.getDept()) || studentDept.equals(r.getDepartment())).count();

            if (event.getDeptSectionLimits() != null && event.getDeptSectionLimits().containsKey(studentDept)) {
                Map<String, Object> sectionLimits = (Map<String, Object>) event.getDeptSectionLimits().get(studentDept);
                if (!sectionLimits.containsKey(studentSec)) {
                    return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: Section " + studentSec + " of " + studentDept + " is not permitted to register."));
                }
                int sectionLimit = Integer.parseInt(sectionLimits.get(studentSec).toString());
                if (sectionLimit <= 0) {
                    return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: Section " + studentSec + " of " + studentDept + " is not permitted to register."));
                }

                long secRegsCount = eventRegs.stream().filter(r -> (studentDept.equals(r.getDept()) || studentDept.equals(r.getDepartment())) && studentSec.equals(r.getSection())).count();
                if (secRegsCount >= sectionLimit) {
                    return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: Quota for Section " + studentSec + " of " + studentDept + " is full."));
                }
            } else {
                if (deptRegsCount >= deptLimit) {
                    return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", "Registration Blocked: Quota for department " + studentDept + " is full."));
                }
            }
        }

        boolean isFree = event.getHasRegistrationFee() == null || !event.getHasRegistrationFee() || event.getRegistrationFee() == 0;
        payload.setId(regId);
        payload.setPaymentStatus(isFree ? "COMPLETED" : "PENDING");
        payload.setCertificationStatus("NOT_SUBMITTED");
        payload.setRegisteredAt(Instant.now().toString());

        registrationRepository.save(payload);

        event.setCurrentParticipants(currentParticipants + 1);
        eventRepository.save(event);

        return ResponseEntity.ok(payload);
    }

    @PutMapping("/{id}")
    public ResponseEntity<?> updateRegistration(@PathVariable String id, @RequestBody Map<String, Object> payload) {
        Optional<Registration> regOpt = registrationRepository.findById(id);
        if (regOpt.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", "Registration not found"));
        }

        Registration reg = regOpt.get();

        if (payload.containsKey("payment_status")) reg.setPaymentStatus((String) payload.get("payment_status"));
        if (payload.containsKey("paymentStatus")) reg.setPaymentStatus((String) payload.get("paymentStatus"));

        if (payload.containsKey("team_code")) reg.setTeamCode((String) payload.get("team_code"));
        if (payload.containsKey("teamCode")) reg.setTeamCode((String) payload.get("teamCode"));

        if (payload.containsKey("team_name")) reg.setTeamName((String) payload.get("team_name"));
        if (payload.containsKey("teamName")) reg.setTeamName((String) payload.get("teamName"));

        if (payload.containsKey("is_team_leader")) reg.setIsTeamLeader((Boolean) payload.get("is_team_leader"));
        if (payload.containsKey("isTeamLeader")) reg.setIsTeamLeader((Boolean) payload.get("isTeamLeader"));

        if (payload.containsKey("certification_url")) reg.setCertificationUrl((String) payload.get("certification_url"));
        if (payload.containsKey("certificationUrl")) reg.setCertificationUrl((String) payload.get("certificationUrl"));

        if (payload.containsKey("certification_status")) reg.setCertificationStatus((String) payload.get("certification_status"));
        if (payload.containsKey("certificationStatus")) reg.setCertificationStatus((String) payload.get("certificationStatus"));

        if (payload.containsKey("od_url")) reg.setOdUrl((String) payload.get("od_url"));
        if (payload.containsKey("odUrl")) reg.setOdUrl((String) payload.get("odUrl"));

        if (payload.containsKey("ticket_id")) reg.setTicketId((String) payload.get("ticket_id"));
        if (payload.containsKey("ticketId")) reg.setTicketId((String) payload.get("ticketId"));

        if (payload.containsKey("ticket_qrcode")) reg.setTicketQrcode((String) payload.get("ticket_qrcode"));
        if (payload.containsKey("ticketQrcode")) reg.setTicketQrcode((String) payload.get("ticketQrcode"));

        registrationRepository.save(reg);
        return ResponseEntity.ok(Map.of("message", "Registration updated successfully", "data", reg));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteRegistration(@PathVariable String id) {
        Optional<Registration> regOpt = registrationRepository.findById(id);
        if (regOpt.isPresent()) {
            Registration reg = regOpt.get();
            Long eventId = reg.getEventId();
            registrationRepository.delete(reg);

            if (eventId != null) {
                Optional<Event> eventOpt = eventRepository.findById(eventId);
                if (eventOpt.isPresent()) {
                    Event event = eventOpt.get();
                    int count = registrationRepository.findByEventId(eventId).size();
                    event.setCurrentParticipants(count);
                    eventRepository.save(event);
                }
            }
        }
        return ResponseEntity.ok(Map.of("message", "Registration deleted successfully"));
    }

    private Instant parseDate(String val) {
        if (val == null || val.trim().isEmpty()) {
            return Instant.now();
        }
        String clean = val.trim().replace(" ", "T");
        if (clean.length() == 10) {
            clean += "T00:00:00";
        }
        if (clean.length() == 16) {
            clean += ":00";
        }
        if (!clean.contains("Z") && !clean.contains("+") && !clean.contains("-")) {
            clean += "Z";
        }
        try {
            return Instant.parse(clean);
        } catch (Exception e) {
            try {
                return java.time.LocalDateTime.parse(clean.substring(0, 19))
                        .toInstant(java.time.ZoneOffset.UTC);
            } catch (Exception ex) {
                return Instant.now();
            }
        }
    }
}
