package com.ffii.lioner.modules.lioner.web;

import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.qr.QrData;
import dev.samstevens.totp.secret.SecretGenerator;

import lombok.RequiredArgsConstructor;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
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;
import org.springframework.web.server.ResponseStatusException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.ffii.lioner.modules.user.entity.User;
import com.ffii.lioner.modules.user.service.UserService;
import com.ffii.lioner.modules.user.service.UserAuthorityService;  // ← ADD THIS IMPORT
import com.ffii.lioner.config.security.jwt.service.JwtUserDetailsService;
import com.ffii.core.utils.JwtTokenUtil;  // ← Use the correct path from your project
import com.ffii.lioner.model.JwtResponse;

@RestController
@RequestMapping("/2fa")
@RequiredArgsConstructor
public class TwoFactorController {

    private final SecretGenerator secretGenerator;
    private final CodeVerifier codeVerifier;
    private final UserService userService;
    private final JwtUserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    private final UserAuthorityService userAuthorityService;

    private static final long TOKEN_DURATION_MINUTES = 5;

    @PostMapping("/setup")
    public Map<String, String> setup2FA(Authentication authentication) {
        User user = userService.getCurrentUser(authentication);

        String secret = secretGenerator.generate();
        user.setTwoFactorSecret(secret);
        user.setTwoFactorEnabled(false);
        userService.save(user);

        QrData data = new QrData.Builder()
                .label(user.getUsername())
                .secret(secret)
                .issuer("Lioner Form Mapping System")
                .build();

        return Map.of("otpauthUrl", data.getUri());
    }

    @PostMapping("/verify-setup")
    public ResponseEntity<?> verifySetup(@RequestBody Map<String, String> request, Authentication auth) {
        String code = request.get("code");
        User user = userService.getCurrentUser(auth);

        if (codeVerifier.isValidCode(user.getTwoFactorSecret(), code)) {
            user.setTwoFactorEnabled(true);
            userService.save(user);
            return ResponseEntity.ok(Map.of("message", "2FA enabled successfully"));
        }
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid verification code");
    }

    @PostMapping("/verify-login")
    public ResponseEntity<?> verifyLogin(@RequestBody Map<String, String> request) {
        String code = request.get("code");
        String username = request.get("username");

        User user = userService.getUserByUsername(username);

        if (!user.isTwoFactorEnabled()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "2FA not enabled for this user");
        }

        if (!codeVerifier.isValidCode(user.getTwoFactorSecret(), code)) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid 2FA code");
        }

        // Generate tokens
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        long accessTokenExpiry = TOKEN_DURATION_MINUTES * 60 * 1000;
        String accessToken = jwtTokenUtil.generateToken(userDetails, accessTokenExpiry);
        String refreshToken = jwtTokenUtil.createRefreshToken(username).getToken();

        // Load abilities — now works because service is injected
        List<String> abilities = new ArrayList<>();
        userAuthorityService.getUserAuthority(user).forEach(auth -> 
            abilities.add(auth.get("authority").toString())
        );

        return ResponseEntity.ok(new JwtResponse(accessToken, refreshToken, null, user, abilities));
    }
}