/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.cts.tv;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assume.assumeTrue;

import android.cts.statsdatom.lib.AtomTestUtils;
import android.cts.statsdatom.lib.ConfigUtils;
import android.cts.statsdatom.lib.DeviceUtils;
import android.cts.statsdatom.lib.ReportUtils;
import android.stats.tv.TifTuneState;

import com.android.os.AtomsProto;
import com.android.os.StatsLog;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.truth.Correspondence;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * Test {@link com.android.server.tv.TvInputManagerService} statsd metrics.
 */
@RunWith(DeviceJUnit4ClassRunner.class)
public class TvInputManagerServiceHostTest extends BaseHostJUnit4Test {
    public static final String TEST_APK = "CtsTvTestCasesHelperApp.apk";
    public static final String TEST_PKG = "android.tv.cts";

    /** Compares the fields state, hdmiPort and inputId */
    private static final Correspondence<AtomsProto.TifTuneStateChanged,
            AtomsProto.TifTuneStateChanged>
            TIF_TUNE_STATE_CHANGED_CORRESPONDENCE = CorrespondenceFieldChainBuilder
            .builder(AtomsProto.TifTuneStateChanged.class)
            .addField(AtomsProto.TifTuneStateChanged::getState, "state")
            .addField(AtomsProto.TifTuneStateChanged::getHdmiPort, "hdmi_port")
            .addField(AtomsProto.TifTuneStateChanged::getInputId, "input_id")
            .build();

    @Rule
    public RequiredFeatureRule requiredFeatureRule = new RequiredFeatureRule(this,
            "android.software.live_tv");

    @Before
    public void setup() throws Exception {
        installPackage(TEST_APK);
        ConfigUtils.removeConfig(getDevice());
        ReportUtils.clearReports(getDevice());
        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
    }

    @After
    public void tearDown() throws Exception {
        ConfigUtils.removeConfig(getDevice());
        ReportUtils.clearReports(getDevice());
        uninstallPackage(TEST_APK);
    }

    @Test
    public void verifyCallbackVideoAvailable() throws Exception {
        ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), TEST_PKG,
                AtomsProto.Atom.TIF_TUNE_CHANGED_FIELD_NUMBER,  /*uidInAttributionChain=*/true);

        runTvInputServiceTest("verifyCallbackVideoAvailable");

        // Sorted list of events in order in which they occurred.
        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
        List<AtomsProto.TifTuneStateChanged> tifTuneStateChanges = Lists.transform(data,
                input -> input.getAtom().getTifTuneChanged());
        AtomsProto.TifTuneStateChanged.Builder protoBuilder =
                AtomsProto.TifTuneStateChanged.newBuilder().
                        setInputId(1).
                        setHdmiPort(0);
        assertThat(tifTuneStateChanges).
                comparingElementsUsing(TIF_TUNE_STATE_CHANGED_CORRESPONDENCE).
                containsExactlyElementsIn(
                        createAtomsFromStateList(protoBuilder,
                                TifTuneState.CREATED,
                                TifTuneState.SURFACE_ATTACHED,
                                TifTuneState.TUNE_STARTED,
                                TifTuneState.VIDEO_AVAILABLE,
                                TifTuneState.SURFACE_DETACHED,
                                TifTuneState.RELEASED)).
                inOrder();
    }

    @Test
    public void verifyCallbackVideoUnavailable() throws Exception {
        ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), TEST_PKG,
                AtomsProto.Atom.TIF_TUNE_CHANGED_FIELD_NUMBER,  /*uidInAttributionChain=*/true);

        runTvInputServiceTest("verifyCallbackVideoUnavailable");

        // Sorted list of events in order in which they occurred.
        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
        List<AtomsProto.TifTuneStateChanged> tifTuneStateChanges = Lists.transform(data,
                input -> input.getAtom().getTifTuneChanged());
        AtomsProto.TifTuneStateChanged.Builder protoBuilder =
                AtomsProto.TifTuneStateChanged.newBuilder().
                        setInputId(1).
                        setHdmiPort(0);
        assertThat(tifTuneStateChanges).
                comparingElementsUsing(TIF_TUNE_STATE_CHANGED_CORRESPONDENCE).
                containsExactlyElementsIn(
                        createAtomsFromStateList(protoBuilder,
                                TifTuneState.CREATED,
                                TifTuneState.SURFACE_ATTACHED,
                                TifTuneState.TUNE_STARTED,
                                TifTuneState.VIDEO_UNAVAILABLE_REASON_TUNING,
                                TifTuneState.SURFACE_DETACHED,
                                TifTuneState.RELEASED)).
                inOrder();
    }

    @Test
    public void verifyCommandTune() throws Exception {
        ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), TEST_PKG,
                AtomsProto.Atom.TIF_TUNE_CHANGED_FIELD_NUMBER,  /*uidInAttributionChain=*/true);

        runTvInputServiceTest("verifyCommandTune");

        // Sorted list of events in order in which they occurred.
        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
        List<AtomsProto.TifTuneStateChanged> tifTuneStateChanges = Lists.transform(data,
                input -> input.getAtom().getTifTuneChanged());
        AtomsProto.TifTuneStateChanged.Builder protoBuilder =
                AtomsProto.TifTuneStateChanged.newBuilder().
                        setInputId(1).
                        setHdmiPort(0);
        assertThat(tifTuneStateChanges).
                comparingElementsUsing(TIF_TUNE_STATE_CHANGED_CORRESPONDENCE).
                containsExactlyElementsIn(
                        createAtomsFromStateList(protoBuilder,
                                TifTuneState.CREATED,
                                TifTuneState.SURFACE_ATTACHED,
                                TifTuneState.TUNE_STARTED,
                                TifTuneState.SURFACE_DETACHED,
                                TifTuneState.RELEASED)).
                inOrder();

    }

    private void runTvInputServiceTest(String testMethodName)
            throws DeviceNotAvailableException {
        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                "android.media.tv.cts.TvInputServiceTest", testMethodName);
    }

    private static Iterable<AtomsProto.TifTuneStateChanged> createAtomsFromStateList(
            AtomsProto.TifTuneStateChanged.Builder protoBuilder, TifTuneState... tuneStates) {
        ImmutableList.Builder<AtomsProto.TifTuneStateChanged> atoms = ImmutableList.builder();
        for (int i = 0; i < tuneStates.length; i++) {
            atoms.add(protoBuilder.setState(tuneStates[i]).build());
        }
        return atoms.build();
    }

    private static class CorrespondenceFieldChainBuilder<T> {
        private static class GetterName<T> {
            private final Function<T, Object> getter;
            private final String name;

            private GetterName(Function<T, Object> getter, String name) {
                this.getter = getter;
                this.name = name;
            }

            boolean isEqual(T actual, T expected) {
                return getter.apply(actual).equals(getter.apply(expected));
            }

            String diff(T actual, T expected) {
                return isEqual(actual, expected) ? ""
                        : String.format(
                                Locale.ENGLISH, "%s Expected: %s  Actual: %s",
                                name, getter.apply(expected),
                                getter.apply(actual));
            }
        }

        private static <T> CorrespondenceFieldChainBuilder<T> builder(
                Class<T> unused) {
            return new CorrespondenceFieldChainBuilder<T>();
        }

        List<GetterName<T>> getterNames = new ArrayList<>();

        CorrespondenceFieldChainBuilder<T> addField(Function<T, Object> getter, String name) {
            getterNames.add(new GetterName(getter, name));
            return this;
        }

        Correspondence<T, T> build() {
            Correspondence.BinaryPredicate<T, T> predicate = (actual, expected) ->
                    Iterables.all(getterNames, input -> input.isEqual(actual, expected));
            Correspondence.DiffFormatter<T, T> formatter =
                    (actual, expected) -> Joiner.on("\n").join(
                            Iterables.transform(getterNames,
                                    input -> input.diff(actual, expected)));
            return Correspondence.from(predicate,
                    "matches fields " + Lists.transform(getterNames,
                            input -> input.name)).formattingDiffsUsing(
                    formatter);
        }
    }

    // TODO(b/180429722): Move to a common CTS location.
    public static class RequiredFeatureRule implements TestRule {

        private final BaseHostJUnit4Test mTest;
        private final String mFeature;

        public RequiredFeatureRule(BaseHostJUnit4Test test, String feature) {
            mTest = test;
            mFeature = feature;
        }

        @Override
        public Statement apply(final Statement base, Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    ITestDevice testDevice = mTest.getDevice();
                    // Checks if the device is available.
                    assumeTrue("Test device is not available", testDevice != null);
                    // Checks if the requested feature is available on the device.
                    assumeTrue(mFeature + " not present in DUT " + testDevice.getSerialNumber(),
                            testDevice.hasFeature(mFeature));
                    base.evaluate();
                }
            };
        }
    }
}
