/*
 * Copyright (c) 2010-2026 Contributors to the openHAB project
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.openhab.binding.evcc.internal.handler;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.openhab.binding.evcc.internal.EvccBindingConstants.*;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
 * Abstract base test for EvccBaseThingHandler implementations.
 * Extend this class in your handler tests and override createHandler().
 *
 * @author Marcel Goerentz - Initial contribution
 */
@SuppressWarnings("null")
@NonNullByDefault
public abstract class AbstractThingHandlerTestClass<T extends EvccBaseThingHandler> {

    protected Thing thing = mock(Thing.class);
    protected ChannelTypeRegistry channelTypeRegistry = mock(ChannelTypeRegistry.class);
    @Nullable
    protected T handler = null;

    protected ThingStatus lastThingStatus = ThingStatus.UNKNOWN;
    protected ThingStatusDetail lastThingStatusDetail = ThingStatusDetail.NONE;

    protected static JsonObject exampleResponse = new JsonObject();
    protected static JsonObject verifyObject = new JsonObject();

    /**
     * Implement this to provide a handler instance for testing.
     */
    protected abstract T createHandler();

    @BeforeAll
    static void setUpOnce() {
        try (InputStream is = EvccBatteryHandlerTest.class.getClassLoader()
                .getResourceAsStream("responses/example_response.json")) {
            if (is == null) {
                throw new IllegalArgumentException("Couldn't find response file");
            }
            String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            exampleResponse = JsonParser.parseString(json).getAsJsonObject();
            verifyObject = exampleResponse.deepCopy();
        } catch (IOException e) {
            fail("Failed to read example response file", e);
        }
    }

    @Nested
    class InitializeTests {

        @BeforeEach
        public void setUp() {
            when(thing.getUID()).thenReturn(new ThingUID("test:thing:uid"));
            when(thing.getProperties()).thenReturn(Map.of("index", "0", "type", "battery", "subType", "solar"));
            when(thing.getChannels()).thenReturn(new ArrayList<>());
            Configuration configuration = mock(Configuration.class);
            when(configuration.get(PROPERTY_INDEX)).thenReturn("0");
            when(configuration.get(PROPERTY_VEHICLE_ID)).thenReturn("vehicle_1");
            when(configuration.get(PROPERTY_SUBTYPE)).thenReturn("solar");
            when(thing.getConfiguration()).thenReturn(configuration);
            handler = spy(createHandler());
        }

        @Test
        public void initializeWithoutBridgeHandler() {
            handler.initialize();
            assertEquals(ThingStatus.OFFLINE, lastThingStatus);
            assertEquals(ThingStatusDetail.BRIDGE_UNINITIALIZED, lastThingStatusDetail);
        }

        @Test
        public void initializeWithBridgeHandlerWithoutCachedState() {
            EvccBridgeHandler bridgeHandler = mock(EvccBridgeHandler.class);
            handler.bridgeHandler = bridgeHandler;
            when(bridgeHandler.getCachedEvccState()).thenReturn(new JsonObject());
            LocaleProvider lp = mock(LocaleProvider.class);
            TranslationProvider tp = mock(TranslationProvider.class);
            Bundle bundle = mock(Bundle.class);
            BundleContext ctx = mock(BundleContext.class);
            when(lp.getLocale()).thenReturn(Locale.ENGLISH);
            when(bridgeHandler.getLocaleProvider()).thenReturn(lp);
            when(bridgeHandler.getI18nProvider()).thenReturn(tp);
            when(bundle.getBundleContext()).thenReturn(ctx);

            handler.initialize();
            assertEquals(ThingStatus.OFFLINE, lastThingStatus);
            assertEquals(ThingStatusDetail.COMMUNICATION_ERROR, lastThingStatusDetail);
        }
    }
}
