<?php

use App\Services\SystemConfig\SettingValueCaster;

test('normalize bool accepts truthy and falsy values', function (mixed $input, bool $expected) {
    expect(SettingValueCaster::normalize($input, 'bool'))->toBe($expected);
})->with([
    ['true', true],
    ['1', true],
    [1, true],
    [true, true],
    ['on', true],
    ['false', false],
    ['0', false],
    [0, false],
    [false, false],
    ['', false],
]);

test('normalize int returns null for empty string and null', function () {
    expect(SettingValueCaster::normalize('', 'int'))->toBeNull();
    expect(SettingValueCaster::normalize(null, 'int'))->toBeNull();
});

test('normalize int casts numeric strings', function () {
    expect(SettingValueCaster::normalize('42', 'int'))->toBe(42);
    expect(SettingValueCaster::normalize('0', 'int'))->toBe(0);
});

test('normalize float casts numeric strings', function () {
    expect(SettingValueCaster::normalize('3.14', 'float'))->toBe(3.14);
});

test('normalize json passes through arrays and parses strings', function () {
    expect(SettingValueCaster::normalize(['a' => 1], 'json'))->toBe(['a' => 1]);
    expect(SettingValueCaster::normalize('{"b":2}', 'json'))->toBe(['b' => 2]);
    expect(SettingValueCaster::normalize('not-json', 'json'))->toBe([]);
});

test('normalize string trims whitespace', function () {
    expect(SettingValueCaster::normalize('  hello  ', 'string'))->toBe('hello');
});

test('normalize image_path returns trimmed string or null', function () {
    expect(SettingValueCaster::normalize(' assets/img/logo.png ', 'image_path'))->toBe('assets/img/logo.png');
    expect(SettingValueCaster::normalize(null, 'image_path'))->toBeNull();
});

test('serialize bool emits 1 or 0', function () {
    expect(SettingValueCaster::serialize(true))->toBe('1');
    expect(SettingValueCaster::serialize(false))->toBe('0');
});

test('serialize null returns null', function () {
    expect(SettingValueCaster::serialize(null))->toBeNull();
});

test('serialize array emits json', function () {
    expect(SettingValueCaster::serialize(['x' => 'y']))->toBe('{"x":"y"}');
});

test('serialize scalar returns string', function () {
    expect(SettingValueCaster::serialize(42))->toBe('42');
    expect(SettingValueCaster::serialize('abc'))->toBe('abc');
});

test('deserialize round-trips bool, int, float, json', function () {
    expect(SettingValueCaster::deserialize('1', 'bool'))->toBeTrue();
    expect(SettingValueCaster::deserialize('0', 'bool'))->toBeFalse();
    expect(SettingValueCaster::deserialize('42', 'int'))->toBe(42);
    expect(SettingValueCaster::deserialize('3.14', 'float'))->toBe(3.14);
    expect(SettingValueCaster::deserialize('{"a":1}', 'json'))->toBe(['a' => 1]);
});

test('deserialize null returns null', function () {
    expect(SettingValueCaster::deserialize(null, 'bool'))->toBeNull();
    expect(SettingValueCaster::deserialize(null, 'json'))->toBeNull();
});

test('isUnchanged compares serialized form', function () {
    expect(SettingValueCaster::isUnchanged(true, '1'))->toBeTrue();
    expect(SettingValueCaster::isUnchanged(false, '0'))->toBeTrue();
    expect(SettingValueCaster::isUnchanged(null, null))->toBeTrue();
    expect(SettingValueCaster::isUnchanged('abc', 'abc'))->toBeTrue();
    expect(SettingValueCaster::isUnchanged('abc', 'xyz'))->toBeFalse();
    expect(SettingValueCaster::isUnchanged(['a' => 1], ['a' => 1]))->toBeTrue();
});
