package ru.yandex.direct.api.v5.entity.vcards;

import com.yandex.direct.api.v5.vcards.AddRequest;
import com.yandex.direct.api.v5.vcards.AddResponse;
import com.yandex.direct.api.v5.vcards.ApiException;
import com.yandex.direct.api.v5.vcards.DeleteRequest;
import com.yandex.direct.api.v5.vcards.DeleteResponse;
import com.yandex.direct.api.v5.vcards.GetRequest;
import com.yandex.direct.api.v5.vcards.GetResponse;
import com.yandex.direct.api.v5.vcards.VCardsPort;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.direct.api.v5.common.ApiPathConverter;
import ru.yandex.direct.api.v5.common.validation.DefectPresentationsHolder;
import ru.yandex.direct.api.v5.entity.GenericApiService;
import ru.yandex.direct.api.v5.entity.vcards.delegate.AddVCardsDelegate;
import ru.yandex.direct.api.v5.entity.vcards.delegate.DeleteVCardsDelegate;
import ru.yandex.direct.api.v5.entity.vcards.delegate.GetVCardsDelegate;
import ru.yandex.direct.api.v5.validation.DefectTypes;
import ru.yandex.direct.api.v5.ws.annotation.ApiMethod;
import ru.yandex.direct.api.v5.ws.annotation.ApiRequest;
import ru.yandex.direct.api.v5.ws.annotation.ApiResponse;
import ru.yandex.direct.api.v5.ws.annotation.ApiServiceEndpoint;
import ru.yandex.direct.api.v5.ws.annotation.ApiServiceType;
import ru.yandex.direct.api.v5.ws.annotation.ServiceType;
import ru.yandex.direct.core.entity.campaign.service.validation.CampaignDefectIds;
import ru.yandex.direct.core.entity.vcard.model.Phone;
import ru.yandex.direct.core.entity.vcard.model.PointOnMap;
import ru.yandex.direct.core.entity.vcard.model.Vcard;
import ru.yandex.direct.core.security.authorization.PreAuthorizeRead;
import ru.yandex.direct.core.security.authorization.PreAuthorizeWrite;
import ru.yandex.direct.validation.defect.ids.NumberDefectIds;
import ru.yandex.direct.validation.defect.ids.StringDefectIds;
import ru.yandex.direct.validation.result.DefectIds;
import ru.yandex.direct.validation.result.MappingPathConverter;
import ru.yandex.direct.validation.result.PathConverter;

/**
 * Сервис по работе с визитными карточками
 * <p>
 * https://tech.yandex.ru/direct/doc/ref-v5/vcards/vcards-docpage/
 */
@ApiServiceEndpoint
@ApiServiceType(type = ServiceType.CLIENT)
public class VCardsEndpoint implements VCardsPort {
    public static final PathConverter PATH_CONVERTER = MappingPathConverter.builder(VCardsEndpoint.class, "")
            .add(ApiPathConverter.getCommonDict())
            .add(Vcard.CAMPAIGN_ID.name(), "CampaignId")
            .add(Vcard.COUNTRY.name(), "Country")
            .add(Vcard.CITY.name(), "City")
            .add(Vcard.COMPANY_NAME.name(), "CompanyName")
            .add(Vcard.WORK_TIME.name(), "WorkTime")

            .add(Vcard.PHONE.name(), "Phone")
            .add(Phone.COUNTRY_CODE.name(), "CountryCode")
            .add(Phone.CITY_CODE.name(), "CityCode")
            .add(Phone.PHONE_NUMBER.name(), "PhoneNumber")
            .add(Phone.EXTENSION.name(), "Extension")

            .add(Vcard.STREET.name(), "Street")
            .add(Vcard.HOUSE.name(), "House")
            .add(Vcard.BUILD.name(), "Building")
            .add(Vcard.APART.name(), "Apartment")

            .add(Vcard.INSTANT_MESSENGER.name(), "InstantMessenger")
            .add(ru.yandex.direct.core.entity.vcard.model.InstantMessenger.TYPE.name(),
                    "MessengerClient")
            .add(ru.yandex.direct.core.entity.vcard.model.InstantMessenger.LOGIN.name(),
                    "MessengerLogin")

            .add(Vcard.EXTRA_MESSAGE.name(), "ExtraMessage")
            .add(Vcard.EMAIL.name(), "ContactEmail")
            .add(Vcard.OGRN.name(), "Ogrn")
            .add(Vcard.METRO_ID.name(), "MetroStationId")

            .add(Vcard.MANUAL_POINT.name(), "PointOnMap")
            .add(PointOnMap.X.name(), "X")
            .add(PointOnMap.Y.name(), "Y")
            .add(PointOnMap.X1.name(), "X1")
            .add(PointOnMap.Y1.name(), "Y1")
            .add(PointOnMap.X2.name(), "X2")
            .add(PointOnMap.Y2.name(), "Y2")

            .add(Vcard.CONTACT_PERSON.name(), "ContactPerson")
            .build();

    public static final DefectPresentationsHolder DEFECT_PRESENTATIONS = DefectPresentationsHolder.builder()
            .register(DefectIds.INVALID_VALUE, t -> VCardDefectTypes.invalidValue())
            .register(StringDefectIds.CANNOT_BE_EMPTY, t -> DefectTypes.absentValueInField())
            .register(StringDefectIds.LENGTH_CANNOT_BE_MORE_THAN_MAX,
                    t -> DefectTypes.lengthOfFieldValueMustNotExceed(t.getMaxLength()))
            .register(NumberDefectIds.MUST_BE_LESS_THEN_OR_EQUAL_TO_MAX, t -> VCardDefectTypes.invalidValue())
            .register(NumberDefectIds.MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN, t -> VCardDefectTypes.invalidValue())
            .register(CampaignDefectIds.Gen.CAMPAIGN_NOT_FOUND, t -> VCardDefectTypes.campaignNotFound())
            .register(CampaignDefectIds.Gen.CAMPAIGN_NO_WRITE_RIGHTS, t -> DefectTypes.noRights())
            .register(CampaignDefectIds.Gen.ARCHIVED_CAMPAIGN_MODIFICATION,
                    t -> VCardDefectTypes.archivedCampaignModification())
            .build();

    private static final String SERVICE_NAME = "vcards";

    private final GenericApiService genericApiService;
    private final AddVCardsDelegate addDelegate;
    private final GetVCardsDelegate getDelegate;
    private final DeleteVCardsDelegate deleteDelegate;

    @Autowired
    public VCardsEndpoint(
            GenericApiService genericApiService,
            AddVCardsDelegate addDelegate,
            GetVCardsDelegate getDelegate,
            DeleteVCardsDelegate deleteDelegate) {
        this.genericApiService = genericApiService;
        this.addDelegate = addDelegate;
        this.getDelegate = getDelegate;
        this.deleteDelegate = deleteDelegate;
    }

    @PreAuthorizeWrite
    @ApiMethod(service = SERVICE_NAME, operation = "add")
    @ApiResponse
    @Override
    public AddResponse add(@ApiRequest AddRequest addRequest) throws ApiException {
        return genericApiService.doAction(addDelegate, addRequest);
    }

    @PreAuthorizeRead
    @ApiMethod(service = SERVICE_NAME, operation = "get")
    @ApiResponse
    @Override
    public GetResponse get(@ApiRequest GetRequest getRequest) throws ApiException {
        return genericApiService.doAction(getDelegate, getRequest);
    }

    @PreAuthorizeWrite
    @ApiMethod(service = SERVICE_NAME, operation = "delete")
    @ApiResponse
    @Override
    public DeleteResponse delete(@ApiRequest DeleteRequest deleteRequest) throws ApiException {
        return genericApiService.doAction(deleteDelegate, deleteRequest);
    }
}
