package ru.yandex.autotests.direct.web.data.converters;

import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;

import ru.yandex.autotests.direct.cmd.data.commons.banner.Banner;
import ru.yandex.autotests.direct.cmd.data.commons.banner.ContactInfo;
import ru.yandex.autotests.direct.cmd.data.commons.banner.TurboLanding;
import ru.yandex.autotests.direct.cmd.data.commons.group.Group;
import ru.yandex.autotests.direct.web.objects.banners.BannerInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.BannerPhraseInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.commons.ContactInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.commons.TurboLandingInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.commons.VideoInfoWeb;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Objects.isNull;
import static ru.yandex.autotests.direct.web.data.converters.CalloutsConverter.toCmdCallouts;
import static ru.yandex.autotests.direct.web.data.converters.CalloutsConverter.toInfoWebCallouts;
import static ru.yandex.autotests.direct.web.data.converters.SiteLinkInfoWebConverter.toExpandedCmdSiteLinks;
import static ru.yandex.autotests.direct.web.data.converters.SiteLinkInfoWebConverter.toInfoWebSiteLinks;
import static ru.yandex.autotests.direct.web.util.beanutils.BeanHelper.copyProperties;

public class BannerInfoWebConverter {
    public static Banner toCmdBanner(BannerInfoWeb bannerInfoWeb) {
        ContactInfo contactInfo = new ContactInfo();
        if (isNull(bannerInfoWeb.getContactInfo())) {
            contactInfo = null;
        } else {
            copyProperties(contactInfo, bannerInfoWeb.getContactInfo());
            contactInfo.setWorkTime(
                    workTimeConverter(bannerInfoWeb.getContactInfo().getWorkTime(), ";", "%02d", "#", ";"));
        }
        TurboLanding turboLanding = null;
        if (bannerInfoWeb.getTurboLanding() != null) {
            turboLanding = new TurboLanding()
                    .withHref(bannerInfoWeb.getTurboLanding().getHref())
                    .withId(bannerInfoWeb.getTurboLanding().getId());
        }
        return new Banner().withCallouts(toCmdCallouts(bannerInfoWeb.getCallouts()))
                .withBid(bannerInfoWeb.getBannerId())
                .withPid(isNull(bannerInfoWeb.getAdGroupID()) ? null : bannerInfoWeb.getAdGroupID().toString())
                .withCid(isNull(bannerInfoWeb.getCampaignId()) ? null : bannerInfoWeb.getCampaignId())
                .withSiteLinks(toExpandedCmdSiteLinks(bannerInfoWeb.getSitelinks()))
                .withDisplayHref(bannerInfoWeb.getDisplayHref())
                .withTitle(bannerInfoWeb.getTitle())
                .withTitleExtension(bannerInfoWeb.getTitleExtension())
                .withBody(bannerInfoWeb.getText())
                .withHref(bannerInfoWeb.getHref())
                .withDomain(bannerInfoWeb.getDomain())
                .withContactInfo(contactInfo)
                .withTurboLanding(turboLanding)
                .withHasVcard(isNull(contactInfo) ? 0 : 1)
                .withGeoNames(bannerInfoWeb.getGeo())
                .withGroupName(bannerInfoWeb.getAdGroupName())
                .withStatusShow(bannerInfoWeb.getStatusShow());
    }


    public static BannerInfoWeb cmdBannerToBannerInfoWeb(Banner banner) {
        return cmdBannerToBannerInfoWeb(banner, new BannerInfoWeb());
    }

    public static BannerInfoWeb cmdBannerToBannerInfoWeb(Banner banner, BannerInfoWeb resultBanner) {
        ContactInfoWeb contactInfoWeb = new ContactInfoWeb();
        if (isNull(banner.getContactInfo())) {
            contactInfoWeb = null;
        } else {
            copyProperties(contactInfoWeb, banner.getContactInfo());
            contactInfoWeb.setPhone(contactInfoWeb.getPhone().replace("-", ""));
            contactInfoWeb.setWorkTime(workTimeConverter(banner.getContactInfo().getWorkTime(), ";|#", "%d", ";", ";"));
        }
        resultBanner.withCallouts(toInfoWebCallouts(banner.getCallouts()))
                .withBannerId(banner.getBid())
                .withAdGroupID(parseLong(banner.getPid()))
                .withCampaignId(banner.getCid())
                .withSitelinks(toInfoWebSiteLinks(banner.getSiteLinks()))
                .withDisplayHref(banner.getDisplayHref())
                .withTitle(banner.getTitle())
                .withTitleExtension(banner.getTitleExtension())
                .withText(banner.getBody())
                .withHref(banner.getHref())
                .withIsActive(banner.getStatusActive())
                .withDomain(banner.getDomain())
                .withContactInfo(contactInfoWeb)
                .withAdGroupName(banner.getGroupName())
                .withStatusShow(banner.getStatusShow());
        //TODO:  с этим надо что то думать потом, сделано для обратной совместимости с BannerPhrasesBlockBemSteps#shouldSeePhrase
        if (!isNull(resultBanner.getPhrases())) {
            Stream.of(resultBanner.getPhrases()).forEach(x -> x.setBannerId(banner.getBid()));
        }
        if (!isNull(banner.getTurboLanding())) {
            resultBanner.withTurboLanding(
                    new TurboLandingInfoWeb()
                            .withHref(banner.getTurboLanding().getHref())
                            .withId(banner.getTurboLanding().getId())
            );
        }
        if (!isNull(banner.getVideoResources())) {
            resultBanner
                    .withVideo(
                    new VideoInfoWeb()
                            .withName(banner.getVideoResources().getName())
                            .withId(banner.getVideoResources().getId())
            );
        }
        return resultBanner;
    }

    public static BannerInfoWeb cmdGroupToBannerInfoWeb(Group group, BannerInfoWeb bannerInfoWeb) {
        BannerInfoWeb result = bannerInfoWeb.withAdGroupName(group.getAdGroupName())
                .withGeo(group.getGeo())
                .withDomain(group.getDomain())
                .withMinusKeywords(CollectionUtils.isEmpty(group.getMinusWords()) ?
                        null :
                        group.getMinusWords().stream().toArray(String[]::new))
                .withPhrases(CollectionUtils.isEmpty(group.getPhrases()) ?
                        null :
                        group.getPhrases().stream().map(PhraseInfoWebConverter::toInfoWebPhrase)
                                .toArray(BannerPhraseInfoWeb[]::new));
        //TODO: с этим надо что то думать потом, сделано для обратной совместимости с BannerPhrasesBlockBemSteps#shouldSeePhrase
        if (result.getPhrases() != null) {
            Stream.of(result.getPhrases()).forEach(x -> {
                x.setAdGroupID(parseLong(group.getAdGroupID()));
                if (!isNull(bannerInfoWeb.getBannerId())) {
                    x.setBannerId(bannerInfoWeb.getBannerId());
                }
            });
        }
        return result;
    }

    public static Group toCmdGroup(BannerInfoWeb bannerInfoWeb) {
        return toCmdGroup(bannerInfoWeb, new Group());
    }

    public static Group toCmdGroup(BannerInfoWeb bannerInfoWeb, Group group) {
        checkArgument(isNull(bannerInfoWeb.getTags()), "конвертация тегов еще не реализaddBannerToGroupована");

        return group.withAdGroupName(Objects.toString(bannerInfoWeb.getAdGroupName(), "Новая группа объявлений"))
                .withAdGroupID(Objects.toString(bannerInfoWeb.getAdGroupID(), "0"))
                .withGeo(bannerInfoWeb.getGeo())
                .withTags(emptyMap())
                .withDomain(bannerInfoWeb.getDomain())
                .withMinusWords(isNull(bannerInfoWeb.getMinusKeywords()) ? emptyList()
                        : Arrays.asList(bannerInfoWeb.getMinusKeywords()))
                .withPhrases(ArrayUtils.isEmpty(bannerInfoWeb.getPhrases()) ?
                        emptyList() :
                        Stream.of(bannerInfoWeb.getPhrases())
                                .map(PhraseInfoWebConverter::toCmdPhrase)
                                .collect(Collectors.toList()));
    }

    /**
     * @param workTime              время работы
     * @param inputDelimiterPattern шаблон регулярного выражения разделителя для времени работы
     * @param formatter             строка форматирования для часов/минут
     * @param outputDelimiter       разделитель часов, минут, дней
     * @param outputGroupDelimiter  разделитель групп
     * @return строка задающая время работы для CMD или API
     * <p>
     * ? - есть в случае если это не последняя группа, отсутствует в противном случае
     * <p>
     * cmd формат: ДЕНЬ1;ДЕНЬ2;ЧАС1;МИНУТЫ1;ЧАС2;МИНУТЫ2#?
     * в cmd часы и минуты должны быть двухзначными числами.
     * <p>
     * api формат: ДЕНЬ1;ДЕНЬ2;ЧАС1;МИНУТЫ1;ЧАС2;МИНУТЫ2;?
     */
    private static String workTimeConverter(String workTime, String inputDelimiterPattern, String formatter,
            String outputDelimiter, String outputGroupDelimiter)
    {
        final int GROUP_LEN = 6;
        String[] values = workTime.split(inputDelimiterPattern);
        StringBuffer acc = new StringBuffer();
        for (int i = 0; i < values.length; i += GROUP_LEN) {
            acc.append(values[i]).append(outputDelimiter)
                    .append(values[i + 1]).append(outputDelimiter)
                    .append(format(formatter, parseInt(values[i + 2]))).append(outputDelimiter)
                    .append(format(formatter, parseInt(values[i + 3]))).append(outputDelimiter)
                    .append(format(formatter, parseInt(values[i + 4]))).append(outputDelimiter)
                    .append(format(formatter, parseInt(values[i + 5]))).append(outputGroupDelimiter);
        }
        acc.setLength(acc.length() - 1);
        return acc.toString();
    }
}
