import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:core/core.dart';

void main() {
  group('KcAppConfig', () {
    test('creates config with required fields', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      expect(config.environment, KcAppEnvironment.fake);
      expect(config.environmentLabel, 'FAKE');
      expect(config.hasWordPressConfig, isFalse);
    });

    test('hasWordPressConfig returns true when all credentials present', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: 'https://example.com',
        wcConsumerKey: 'ck_test',
        wcConsumerSecret: 'cs_test',
      );

      expect(config.hasWordPressConfig, isTrue);
      expect(config.environmentLabel, 'WP');
    });

    test('hasWordPressConfig returns false when any credential is missing', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: 'https://example.com',
        wcConsumerKey: '',
        wcConsumerSecret: 'cs_test',
      );

      expect(config.hasWordPressConfig, isFalse);
    });

    test('equality compares all fields', () {
      const a = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );
      const b = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );
      const c = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      expect(a, equals(b));
      expect(a, isNot(equals(c)));
      expect(a.hashCode, equals(b.hashCode));
    });

    test('toString includes environment and hasWordPressConfig', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      expect(config.toString(), contains('fake'));
      expect(config.toString(), contains('hasWordPressConfig: false'));
    });
  });

  group('KcAppEnvironment', () {
    test('fromString parses known values', () {
      expect(KcAppEnvironment.fromString('fake'), KcAppEnvironment.fake);
      expect(KcAppEnvironment.fromString('wordpress'), KcAppEnvironment.wordpress);
    });

    test('fromString is case-insensitive', () {
      expect(KcAppEnvironment.fromString('FAKE'), KcAppEnvironment.fake);
      expect(KcAppEnvironment.fromString('WordPress'), KcAppEnvironment.wordpress);
    });

    test('fromString defaults to fake for unknown values', () {
      expect(KcAppEnvironment.fromString('unknown'), KcAppEnvironment.fake);
      expect(KcAppEnvironment.fromString(''), KcAppEnvironment.fake);
    });

    test('label returns expected display string', () {
      expect(KcAppEnvironment.fake.label, 'FAKE');
      expect(KcAppEnvironment.wordpress.label, 'WP');
    });

    test('key returns expected raw string', () {
      expect(KcAppEnvironment.fake.key, 'fake');
      expect(KcAppEnvironment.wordpress.key, 'wordpress');
    });
  });

  group('KcAppServices', () {
    test('abstract base can be extended', () {
      final services = _TestAppServices();
      expect(services, isA<KcAppServices>());
    });
  });

  group('KcServiceFactory', () {
    test('createFake returns fake services', () {
      final factory = KcServiceFactory<_TestAppServices>(
        createFake: () => _TestAppServices(mode: 'fake'),
        createWordPress: (config) => _TestAppServices(mode: 'wp'),
      );

      final services = factory.createFake();
      expect(services.mode, 'fake');
    });

    test('createWordPress returns wordpress services', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: 'https://example.com',
        wcConsumerKey: 'ck_test',
        wcConsumerSecret: 'cs_test',
      );
      final factory = KcServiceFactory<_TestAppServices>(
        createFake: () => _TestAppServices(mode: 'fake'),
        createWordPress: (cfg) => _TestAppServices(mode: 'wp-${cfg.wcSiteUrl}'),
      );

      final services = factory.createWordPress(config);
      expect(services.mode, 'wp-https://example.com');
    });
  });

  group('KcBootstrap', () {
    late KcServiceFactory<_TestAppServices> factory;

    setUp(() {
      factory = KcServiceFactory<_TestAppServices>(
        createFake: () => _TestAppServices(mode: 'fake'),
        createWordPress: (config) => _TestAppServices(mode: 'wp'),
      );
    });

    test('fake environment returns fake services', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      final result = KcBootstrap.run(config, factory);

      expect(result.services.mode, 'fake');
      expect(result.config.environment, KcAppEnvironment.fake);
    });

    test('wordpress environment with valid credentials returns wp services', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: 'https://example.com',
        wcConsumerKey: 'ck_test',
        wcConsumerSecret: 'cs_test',
      );

      final result = KcBootstrap.run(config, factory);

      expect(result.services.mode, 'wp');
      expect(result.config.environment, KcAppEnvironment.wordpress);
    });

    test('wordpress environment without credentials falls back to fake', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      final result = KcBootstrap.run(config, factory);

      expect(result.services.mode, 'fake');
      expect(result.config.environment, KcAppEnvironment.fake);
    });

    test('wordpress fallback preserves partial credentials in config', () {
      const config = KcAppConfig(
        environment: KcAppEnvironment.wordpress,
        wcSiteUrl: 'https://example.com',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      final result = KcBootstrap.run(config, factory);

      expect(result.services.mode, 'fake');
      expect(result.config.environment, KcAppEnvironment.fake);
      expect(result.config.wcSiteUrl, 'https://example.com');
    });
  });

  group('KcAppScope', () {
    testWidgets('of<T> retrieves typed services from widget tree', (tester) async {
      final services = _TestAppServices(mode: 'test');
      const config = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      late _TestAppServices retrievedServices;
      late KcAppConfig retrievedConfig;

      await tester.pumpWidget(
        KcAppScope<_TestAppServices>(
          services: services,
          config: config,
          child: Builder(
            builder: (context) {
              retrievedServices = KcAppScope.of<_TestAppServices>(context);
              retrievedConfig = KcAppScope.configOf<_TestAppServices>(context);
              return const SizedBox.shrink();
            },
          ),
        ),
      );

      expect(retrievedServices.mode, 'test');
      expect(retrievedConfig.environment, KcAppEnvironment.fake);
    });

    testWidgets('updateShouldNotify returns true when services change', (tester) async {
      final scope1 = KcAppScope<_TestAppServices>(
        services: _TestAppServices(mode: 'a'),
        config: const KcAppConfig(
          environment: KcAppEnvironment.fake,
          wcSiteUrl: '',
          wcConsumerKey: '',
          wcConsumerSecret: '',
        ),
        child: const SizedBox.shrink(),
      );
      final scope2 = KcAppScope<_TestAppServices>(
        services: _TestAppServices(mode: 'b'),
        config: const KcAppConfig(
          environment: KcAppEnvironment.fake,
          wcSiteUrl: '',
          wcConsumerKey: '',
          wcConsumerSecret: '',
        ),
        child: const SizedBox.shrink(),
      );

      expect(scope1.updateShouldNotify(scope2), isTrue);
    });

    testWidgets('updateShouldNotify returns false when identical', (tester) async {
      final services = _TestAppServices(mode: 'same');
      const config = KcAppConfig(
        environment: KcAppEnvironment.fake,
        wcSiteUrl: '',
        wcConsumerKey: '',
        wcConsumerSecret: '',
      );

      final scope1 = KcAppScope<_TestAppServices>(
        services: services,
        config: config,
        child: const SizedBox.shrink(),
      );
      final scope2 = KcAppScope<_TestAppServices>(
        services: services,
        config: config,
        child: const SizedBox.shrink(),
      );

      expect(scope1.updateShouldNotify(scope2), isFalse);
    });
  });
}

/// A minimal concrete [KcAppServices] subclass for testing.
class _TestAppServices extends KcAppServices {
  final String mode;
  const _TestAppServices({this.mode = 'default'});
}
