package ru.yandex.direct.web.entity.smsauth.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import ru.yandex.direct.common.util.HttpUtil;
import ru.yandex.direct.core.security.DirectAuthentication;
import ru.yandex.direct.validation.result.Defect;
import ru.yandex.direct.validation.result.ValidationResult;
import ru.yandex.direct.web.core.model.WebResponse;
import ru.yandex.direct.web.core.security.DirectWebAuthenticationSource;
import ru.yandex.direct.web.entity.smsauth.model.SmsAuthBaseInternalRequest;
import ru.yandex.direct.web.entity.smsauth.model.checkpassword.CheckPasswordInternalRequest;
import ru.yandex.direct.web.entity.smsauth.model.checkpassword.CheckPasswordRequest;
import ru.yandex.direct.web.entity.smsauth.model.getsmsphone.GetSmsPhoneResponse;
import ru.yandex.direct.web.entity.smsauth.model.getsmsphone.GetSmsPhoneResult;
import ru.yandex.direct.web.entity.smsauth.model.sendsms.SendSmsByPhoneIdInternalRequest;
import ru.yandex.direct.web.entity.smsauth.model.sendsms.SendSmsByPhoneIdRequest;
import ru.yandex.direct.web.entity.smsauth.model.sendsms.SendSmsResponse;
import ru.yandex.direct.web.entity.smsauth.model.sendsms.SendSmsResult;
import ru.yandex.direct.web.validation.kernel.ValidationResultConversionService;

import static ru.yandex.direct.common.util.HttpUtil.getCookieValue;
import static ru.yandex.direct.utils.HashingUtils.getMd5HashUtf8AsHexString;
import static ru.yandex.direct.web.auth.blackbox.BlackboxCookieCredentials.SESSION_ID;

@Service
public class SmsAuthControllerService {

    private static final Logger logger = LoggerFactory.getLogger(SmsAuthControllerService.class);

    private final SmsAuthService smsAuthService;
    private final DirectWebAuthenticationSource authenticationSource;
    private final SmsAuthValidationService smsAuthValidationService;
    private final ValidationResultConversionService validationResultConversionService;

    @Autowired
    public SmsAuthControllerService(SmsAuthService smsAuthService,
                                    DirectWebAuthenticationSource authenticationSource,
                                    SmsAuthValidationService smsAuthValidationService,
                                    ValidationResultConversionService validationResultConversionService) {
        this.smsAuthService = smsAuthService;
        this.authenticationSource = authenticationSource;
        this.smsAuthValidationService = smsAuthValidationService;
        this.validationResultConversionService = validationResultConversionService;
    }

    public ResponseEntity<WebResponse> getSmsPhone() {
        Long operatorUid = authenticationSource.getAuthentication().getOperator().getUid();
        GetSmsPhoneResult result = smsAuthService.getSmsPhone(operatorUid);

        return new ResponseEntity<>(new GetSmsPhoneResponse(result), HttpStatus.OK);
    }

    public ResponseEntity<WebResponse> sendSms(SendSmsByPhoneIdRequest request) {
        DirectAuthentication authentication = authenticationSource.getAuthentication();
        String sessionIdHash = getMd5HashUtf8AsHexString(getCookieValue(SESSION_ID, HttpUtil.getRequest()).get());
        SendSmsByPhoneIdInternalRequest internalRequest =
                new SendSmsByPhoneIdInternalRequest(authentication.getOperator().getUid(),
                        request.getPhoneId(), sessionIdHash);

        try {
            ValidationResult<SmsAuthBaseInternalRequest, Defect> preValidationResult =
                    smsAuthValidationService.preValidate(internalRequest);
            if (preValidationResult.hasAnyErrors()) {
                return new ResponseEntity<>(
                        validationResultConversionService.buildValidationResponse(preValidationResult),
                        HttpStatus.BAD_REQUEST);
            }
            ValidationResult<SendSmsByPhoneIdInternalRequest, Defect> validationResult =
                    smsAuthValidationService.validate(internalRequest);
            if (validationResult.hasAnyErrors()) {
                return new ResponseEntity<>(validationResultConversionService.buildValidationResponse(validationResult),
                        HttpStatus.BAD_REQUEST);
            }

            SendSmsResult result = smsAuthService.sendSms(internalRequest);

            if (!result.isSuccessful()) {
                logger.error("Got unexpected error sending sms. Error: {}, error code: {}. Operator uid: {}",
                        result.getError(), result.getErrorCode(), internalRequest.getOperatorUid());

                return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
            }

            return new ResponseEntity<>(new SendSmsResponse(result), HttpStatus.OK);
        } finally {
            smsAuthService.unlockSession(internalRequest);
        }
    }

    public ResponseEntity<WebResponse> checkPassword(CheckPasswordRequest request) {
        DirectAuthentication authentication = authenticationSource.getAuthentication();
        String sessionIdHash = getMd5HashUtf8AsHexString(getCookieValue(SESSION_ID, HttpUtil.getRequest()).get());
        CheckPasswordInternalRequest internalRequest =
                new CheckPasswordInternalRequest(authentication.getOperator().getUid(),
                        sessionIdHash, request.getPassword());

        try {
            ValidationResult<SmsAuthBaseInternalRequest, Defect> preValidationResult =
                    smsAuthValidationService.preValidate(internalRequest);
            if (preValidationResult.hasAnyErrors()) {
                return new ResponseEntity<>(validationResultConversionService.buildValidationResponse(preValidationResult),
                        HttpStatus.BAD_REQUEST);
            }
            ValidationResult<CheckPasswordInternalRequest, Defect> validationResult =
                    smsAuthValidationService.validate(internalRequest);
            if (validationResult.hasAnyErrors()) {
                return new ResponseEntity<>(validationResultConversionService.buildValidationResponse(validationResult),
                        HttpStatus.BAD_REQUEST);
            }

            smsAuthService.completeAuthentication(internalRequest);

            return new ResponseEntity<>(HttpStatus.OK);
        } finally {
            smsAuthService.unlockSession(internalRequest);
        }
    }
}
