package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.dto.auth.ForgotPasswordRequestDto;
import com.gnx.telemedicine.dto.auth.JwtResponseDto;
import com.gnx.telemedicine.dto.auth.PasswordResetResponseDto;
import com.gnx.telemedicine.dto.auth.RefreshTokenRequestDto;
import com.gnx.telemedicine.dto.auth.RefreshTokenResponseDto;
import com.gnx.telemedicine.dto.auth.ResetPasswordRequestDto;
import com.gnx.telemedicine.dto.auth.UserLoginDto;
import com.gnx.telemedicine.service.AuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v3/auth")
@RequiredArgsConstructor
@Tag(name = "Authentication", description = "Endpoints for user authentication and authorization")
public class AuthController {

    private final AuthService authService;
    
    @Value("${jwt.cookie.enabled:true}")
    private boolean cookieEnabled;
    
    @Value("${jwt.cookie.name:jwtToken}")
    private String cookieName;
    
    @Value("${jwt.cookie.max-age:86400}")
    private int cookieMaxAge;

    @Operation(
            summary = "User login",
            description = """
                    Authenticate a user with email and password to receive a JWT token.
                    The token should be used in the Authorization header for subsequent requests.
                    """,
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "User login credentials(email/password)",
                    required = true,
                    content = @Content(schema = @Schema(implementation = UserLoginDto.class))
            )
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "User logged in successfully, JWT returned",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = JwtResponseDto.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "401",
                    description = "Invalid email or password",
                    content = @Content(mediaType = "application/json")
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Validation error",
                    content = @Content(mediaType = "application/json")
            )
    })
    @PostMapping("/login")
    public ResponseEntity<JwtResponseDto> login(@Valid @RequestBody UserLoginDto userLoginDto, 
                                                 HttpServletRequest request,
                                                 HttpServletResponse response) {
        JwtResponseDto jwtResponse = authService.login(userLoginDto, request);
        
        // Set httpOnly cookie for enhanced security (XSS protection)
        if (cookieEnabled) {
            jakarta.servlet.http.Cookie cookie = new jakarta.servlet.http.Cookie(cookieName, jwtResponse.token());
            cookie.setHttpOnly(true);
            cookie.setSecure(request.isSecure() || "https".equalsIgnoreCase(request.getScheme()));
            cookie.setPath("/");
            cookie.setMaxAge(cookieMaxAge);
            // Set SameSite attribute to prevent CSRF
            response.setHeader("Set-Cookie", 
                String.format("%s=%s; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=%d",
                    cookieName, jwtResponse.token(), cookieMaxAge));
        }
        
        return ResponseEntity.ok(jwtResponse);
    }

    @Operation(
            summary = "User logout",
            description = "Log out the currently authenticated user and set status to OFFLINE.",
            security = @io.swagger.v3.oas.annotations.security.SecurityRequirement(name = "bearerAuth")
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "User logged out successfully"
            ),
            @ApiResponse(
                    responseCode = "401",
                    description = "Unauthorized - Missing or expired JWT"
            )
    })
    @PostMapping("/logout")
    public ResponseEntity<Void> logout(Authentication authentication) {
        String email = authentication.getName();
        authService.logout(email);
        return ResponseEntity.ok().build();
    }

    @Operation(
            summary = "Request password reset",
            description = "Request a password reset link to be sent to the user's email address."
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Password reset email sent (if email exists)",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = PasswordResetResponseDto.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Validation error",
                    content = @Content(mediaType = "application/json")
            )
    })
    @PostMapping("/forgot-password")
    public ResponseEntity<PasswordResetResponseDto> forgotPassword(@Valid @RequestBody ForgotPasswordRequestDto request) {
        return ResponseEntity.ok(authService.forgotPassword(request));
    }

    @Operation(
            summary = "Reset password",
            description = "Reset password using the token received via email."
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Password reset successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = PasswordResetResponseDto.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Validation error or invalid/expired token",
                    content = @Content(mediaType = "application/json")
            )
    })
    @PostMapping("/reset-password")
    public ResponseEntity<PasswordResetResponseDto> resetPassword(@Valid @RequestBody ResetPasswordRequestDto request) {
        return ResponseEntity.ok(authService.resetPassword(request));
    }

    @Operation(
            summary = "Refresh access token",
            description = "Refresh the access token using a valid refresh token. Returns a new access token."
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Token refreshed successfully",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = RefreshTokenResponseDto.class)
                    )
            ),
            @ApiResponse(
                    responseCode = "401",
                    description = "Invalid or expired refresh token",
                    content = @Content(mediaType = "application/json")
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "Validation error",
                    content = @Content(mediaType = "application/json")
            )
    })
    @PostMapping("/refresh")
    public ResponseEntity<RefreshTokenResponseDto> refreshToken(
            @Valid @RequestBody RefreshTokenRequestDto request,
            HttpServletRequest httpRequest) {
        RefreshTokenResponseDto response = authService.refreshToken(request, httpRequest);
        return ResponseEntity.ok(response);
    }
}
