/*
 * Copyright (c) 2025
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import 'dart:io';
import 'dart:typed_data';

import 'package:flutter_test/flutter_test.dart';
import 'package:splash_video/splash_video.dart';

void main() {
  group('AssetSource', () {
    test('creates with valid path', () {
      final source = AssetSource('assets/videos/splash.mp4');
      expect(source.path, equals('assets/videos/splash.mp4'));
    });

    test('setSource completes without error', () async {
      final source = AssetSource('assets/videos/splash.mp4');
      await expectLater(source.setSource(), completes);
    });
  });

  group('DeviceFileSource', () {
    test('creates with valid path', () {
      final source = DeviceFileSource('/path/to/video.mp4');
      expect(source.path, equals('/path/to/video.mp4'));
    });

    test('setSource creates File object', () async {
      final source = DeviceFileSource('/path/to/video.mp4');
      await source.setSource();
      expect(source.file, isA<File>());
      expect(source.file.path, equals('/path/to/video.mp4'));
    });
  });

  group('NetworkFileSource', () {
    test('creates with valid URL', () {
      final source = NetworkFileSource('https://example.com/video.mp4');
      expect(source.path, equals('https://example.com/video.mp4'));
      expect(source.url, isNotNull);
      expect(source.url.toString(), equals('https://example.com/video.mp4'));
    });

    test('throws exception for invalid URL', () {
      expect(
        () => NetworkFileSource('not a valid url :::'),
        throwsA(isA<SplashVideoException>()),
      );
    });

    test('handles URLs with query parameters', () {
      final source = NetworkFileSource(
        'https://example.com/video.mp4?token=abc123',
      );
      expect(source.url, isNotNull);
      expect(source.url!.queryParameters['token'], equals('abc123'));
    });

    test('handles URLs with special characters', () {
      final source = NetworkFileSource(
        'https://example.com/video%20with%20spaces.mp4',
      );
      expect(source.url, isNotNull);
    });
  });

  group('BytesSource', () {
    test('creates with byte data', () {
      final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
      final source = BytesSource(bytes);
      expect(source.bytes, equals(bytes));
    });

    test('handles empty bytes', () {
      final bytes = Uint8List(0);
      final source = BytesSource(bytes);
      expect(source.bytes.isEmpty, isTrue);
    });

    test('handles large byte arrays', () {
      final bytes = Uint8List(1024 * 1024); // 1MB
      final source = BytesSource(bytes);
      expect(source.bytes.length, equals(1024 * 1024));
    });
  });

  group('Source type safety', () {
    test('sealed class prevents external subclassing', () {
      // This is enforced at compile time, so we just verify types exist
      final sources = <Source>[
        AssetSource('test.mp4'),
        DeviceFileSource('/test.mp4'),
        NetworkFileSource('https://example.com/test.mp4'),
        BytesSource(Uint8List(0)),
      ];

      expect(sources.length, equals(4));
      expect(sources[0], isA<AssetSource>());
      expect(sources[1], isA<DeviceFileSource>());
      expect(sources[2], isA<NetworkFileSource>());
      expect(sources[3], isA<BytesSource>());
    });
  });
}
