<?php

use App\Models\Label;
use App\Models\Macro;
use App\Models\MacroAssignment;
use App\Models\Service;
use App\Models\ServiceMacroAssignment;
use App\Models\ServiceMacroOverride;
use App\Services\MacroResolutionService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('returns empty when no assignments exist', function () {
    $service = Service::factory()->create();
    $resolver = app(MacroResolutionService::class);
    expect($resolver->resolveAssignmentsForPart($service, 'song'))->toBeEmpty();
});

test('returns global assignments when no override', function () {
    $service = Service::factory()->create();
    $macro = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);
    $resolved = $resolver->resolveAssignmentsForPart($service, 'song');

    expect($resolved)->toHaveCount(1);
    expect($resolved->first()->macro->id)->toBe($macro->id);
});

test('override wins over globals', function () {
    $service = Service::factory()->create();
    $macroA = Macro::factory()->create(['name' => 'Global']);
    $macroB = Macro::factory()->create(['name' => 'Override']);
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macroA->id, 'position' => 'all_slides', 'order' => 0]);
    ServiceMacroOverride::create(['service_id' => $service->id, 'part_type' => 'song']);
    ServiceMacroAssignment::create(['service_id' => $service->id, 'part_type' => 'song', 'macro_id' => $macroB->id, 'position' => 'all_slides', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);
    $resolved = $resolver->resolveAssignmentsForPart($service, 'song');

    expect($resolved)->toHaveCount(1);
    expect($resolved->first()->macro->name)->toBe('Override');
});

test('hidden macros are filtered out', function () {
    $service = Service::factory()->create();
    $macro = Macro::factory()->create(['hidden_at' => now()]);
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);
    expect($resolver->resolveAssignmentsForPart($service, 'song'))->toBeEmpty();
});

test('macrosForSlide with all_slides matches every slide', function () {
    $service = Service::factory()->create();
    $macro = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);
    $result = $resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]);

    expect($result)->toHaveCount(1);
    expect($result[0]['uuid'])->toBe($macro->uuid);
});

test('macrosForSlide with first_slide only matches index 0', function () {
    $service = Service::factory()->create();
    $macro = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'first_slide', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);

    expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]))->toHaveCount(1);
    expect($resolver->macrosForSlide($service, 'song', ['index' => 1, 'total' => 3, 'label_id' => null]))->toHaveCount(0);
});

test('macrosForSlide stacking — multiple matching assignments produce multiple macros', function () {
    $service = Service::factory()->create();
    $macro1 = Macro::factory()->create();
    $macro2 = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro1->id, 'position' => 'all_slides', 'order' => 0]);
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro2->id, 'position' => 'first_slide', 'order' => 1]);

    $resolver = app(MacroResolutionService::class);
    $result = $resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]);

    expect($result)->toHaveCount(2);
});

test('macrosForSlide with by_label matches only matching label_id', function () {
    $service = Service::factory()->create();
    $label = Label::factory()->create();
    $macro = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'by_label', 'label_id' => $label->id, 'order' => 0]);

    $resolver = app(MacroResolutionService::class);

    expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => $label->id]))->toHaveCount(1);
    expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => 9999]))->toHaveCount(0);
});

test('countAssignmentsForPart returns correct count', function () {
    $service = Service::factory()->create();
    $macro = Macro::factory()->create();
    MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
    MacroAssignment::create(['part_type' => 'sermon', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);

    $resolver = app(MacroResolutionService::class);

    expect($resolver->countAssignmentsForPart($service, 'song'))->toBe(1);
    expect($resolver->countAssignmentsForPart($service, 'sermon'))->toBe(1);
    expect($resolver->countAssignmentsForPart($service, 'information'))->toBe(0);
});
