package online.wesal.wesal.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import online.wesal.wesal.dto.CreateUserRequest;
import online.wesal.wesal.dto.LoginRequest;
import online.wesal.wesal.dto.LoginResponse;
import online.wesal.wesal.dto.UpdateUserRequest;
import online.wesal.wesal.dto.UsernameSelectionRequest;
import online.wesal.wesal.dto.CheckInvitationRequest;
import online.wesal.wesal.dto.RegisterRequest;
import online.wesal.wesal.dto.RegisterResponse;
import online.wesal.wesal.entity.User;
import online.wesal.wesal.entity.InvitationCode;
import online.wesal.wesal.service.AuthService;
import online.wesal.wesal.service.UserService;
import online.wesal.wesal.service.InvitationCodeService;
import online.wesal.wesal.config.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping("/")
@CrossOrigin(origins = "*")
@Tag(name = "Authentication", description = "Authentication endpoints")
public class AuthController {
    
    @Autowired
    private AuthService authService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private InvitationCodeService invitationCodeService;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @GetMapping("/")
    @Operation(summary = "Health check", description = "Returns API status")
    public ResponseEntity<Map<String, Integer>> healthCheck() {
        return ResponseEntity.ok(Map.of("status", 200));
    }
    
    @PostMapping("/login")
    @Operation(summary = "User login", description = "Authenticate user with phone number or username and return JWT token")
    public ResponseEntity<LoginResponse> login(@Valid @RequestBody LoginRequest loginRequest) {
        try {
            String token = authService.authenticate(loginRequest.getPhoneNumberOrUsername(), loginRequest.getPassword());
            return ResponseEntity.ok(new LoginResponse(token));
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    @PostMapping("/set-username")
    @Operation(summary = "Set username", description = "Set username for authenticated user (can only be done once)")
    public ResponseEntity<User> setUsername(@Valid @RequestBody UsernameSelectionRequest request) {
        try {
            User user = userService.setUsername(request.getUsername());
            return ResponseEntity.ok(user);
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    @GetMapping("/getUser")
    @Operation(summary = "Get current user", description = "Returns the authenticated user's details")
    public ResponseEntity<User> getUser() {
        try {
            User user = userService.getCurrentUser();
            return ResponseEntity.ok(user);
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    @PostMapping("/updateUser")
    @Operation(summary = "Update user information", description = "Update authenticated user's fcmToken, displayName, avatar, password, username, or subscriptions")
    public ResponseEntity<Map<String, Object>> updateUser(@Valid @RequestBody UpdateUserRequest request) {
        try {
            User user = userService.updateUser(
                request.getFcmToken(),
                request.getDisplayName(),
                request.getAvatar(),
                request.getPassword(),
                request.getUsername(),
                request.getSubscriptions()
            );
            
            // Create user data without password
            Map<String, Object> userData = Map.of(
                "id", user.getId(),
                "phoneNumber", user.getPhoneNumber(),
                "username", user.getUsername() != null ? user.getUsername() : "",
                "displayName", user.getDisplayName(),
                "avatar", user.getAvatar() != null ? user.getAvatar() : "",
                "fcmToken", user.getFcmToken() != null ? user.getFcmToken() : "",
                "activated", user.isActivated(),
                "role", user.getRole(),
                "subscriptions", user.getSubscriptions()
            );
            
            return ResponseEntity.ok(Map.of(
                "status", true,
                "message", "Profile updated successfully",
                "data", userData
            ));
        } catch (RuntimeException e) {
            return ResponseEntity.ok(Map.of(
                "status", false,
                "message", e.getMessage()
            ));
        }
    }
    
    @PostMapping("/checkInvitation")
    @Operation(summary = "Check invitation code", description = "Validates if an invitation code is valid and not expired")
    public ResponseEntity<Map<String, Object>> checkInvitation(@Valid @RequestBody CheckInvitationRequest request) {
        try {
            boolean isValid = invitationCodeService.isValidCode(request.getCode());
            if (isValid) {
                return ResponseEntity.ok(Map.of(
                    "status", true,
                    "message", "Invitation code is valid",
                    "data", Map.of("code", request.getCode(), "valid", true)
                ));
            } else {
                return ResponseEntity.ok(Map.of(
                    "status", false,
                    "message", "Invalid or expired invitation code",
                    "data", Map.of("code", request.getCode(), "valid", false)
                ));
            }
        } catch (Exception e) {
            return ResponseEntity.ok(Map.of(
                "status", false,
                "message", "Error validating invitation code"
            ));
        }
    }
    
    @PostMapping("/register")
    @Operation(summary = "Register new user", description = "Register a new user with invitation code, phone number, and password")
    public ResponseEntity<Map<String, Object>> register(@Valid @RequestBody RegisterRequest request) {
        try {
            User user = invitationCodeService.registerUserWithCode(
                request.getCode(),
                request.getPhoneNumber(),
                request.getPassword()
            );
            
            // Auto-login: generate JWT token
            String token = jwtUtil.generateToken(user.getPhoneNumber());
            
            RegisterResponse registerResponse = new RegisterResponse(user, token);
            
            return ResponseEntity.ok(Map.of(
                "status", true,
                "message", "User registered successfully",
                "data", registerResponse
            ));
            
        } catch (RuntimeException e) {
            String message;
            if (e.getMessage().contains("already exists")) {
                message = "A user with this phone number already exists";
            } else if (e.getMessage().contains("Invalid or expired")) {
                message = "Invalid or expired invitation code";
            } else {
                message = "Registration failed. Please try again";
            }
            
            return ResponseEntity.ok(Map.of(
                "status", false,
                "message", message
            ));
        }
    }
    
    @PostMapping("/admin/createUser")
    @Operation(summary = "Create new user (Admin only)", description = "Creates a new user - requires admin privileges")
    public ResponseEntity<?> createUser(@Valid @RequestBody CreateUserRequest request) {
        try {
            User user = userService.createUser(request.getPhoneNumber(), request.getPassword(), request.getDisplayName());
            return ResponseEntity.ok(user);
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
        }
    }
    
    @PostMapping("/admin/createInvitationCode")
    @Operation(summary = "Create invitation code (Admin only)", description = "Generates a new invitation code - requires admin privileges")
    public ResponseEntity<Map<String, Object>> createInvitationCode() {
        try {
            InvitationCode invitationCode = invitationCodeService.generateInvitationCode();
            
            return ResponseEntity.ok(Map.of(
                "status", true,
                "message", "Invitation code created successfully",
                "data", invitationCode
            ));
            
        } catch (RuntimeException e) {
            String message;
            if (e.getMessage().contains("Unable to generate unique")) {
                message = "Failed to generate unique invitation code. Please try again.";
            } else {
                message = "Failed to create invitation code. Please try again.";
            }
            
            return ResponseEntity.ok(Map.of(
                "status", false,
                "message", message
            ));
        }
    }
}