<?php

namespace Tests\Feature;

use App\Models\Automation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AutomationTest extends TestCase
{
    use RefreshDatabase;

    private User $user;

    protected function setUp(): void
    {
        parent::setUp();
        $this->user = User::factory()->create();
        $this->actingAs($this->user);
    }

    // ── Model Tests ──────────────────────────────────────────────

    public function test_automation_can_be_created(): void
    {
        $automation = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Termin-Erinnerung',
            'active'  => true,
            'config'  => ['minutes_before' => 30, 'channel' => 'in_app'],
        ]);

        $this->assertDatabaseHas('automations', [
            'id'      => $automation->id,
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'active'  => true,
        ]);
    }

    public function test_automation_has_uuid_primary_key(): void
    {
        $automation = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'daily_agenda',
            'name'    => 'Tägliche Agenda',
            'active'  => true,
            'config'  => ['send_time' => '08:00', 'channel' => 'email'],
        ]);

        $this->assertNotNull($automation->id);
        $this->assertMatchesRegularExpression(
            '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/',
            $automation->id
        );
    }

    public function test_automation_config_is_cast_to_array(): void
    {
        $automation = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Test',
            'active'  => true,
            'config'  => ['minutes_before' => 15, 'channel' => 'email'],
        ]);

        $automation->refresh();
        $this->assertIsArray($automation->config);
        $this->assertEquals(15, $automation->config['minutes_before']);
        $this->assertEquals('email', $automation->config['channel']);
    }

    public function test_cfg_helper_returns_config_values(): void
    {
        $automation = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Test',
            'active'  => true,
            'config'  => ['minutes_before' => 60, 'channel' => 'in_app'],
        ]);

        $this->assertEquals(60, $automation->cfg('minutes_before'));
        $this->assertEquals('in_app', $automation->cfg('channel'));
        $this->assertNull($automation->cfg('nonexistent'));
        $this->assertEquals('fallback', $automation->cfg('nonexistent', 'fallback'));
    }

    public function test_automation_belongs_to_user(): void
    {
        $automation = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'daily_summary',
            'name'    => 'Test',
            'active'  => true,
            'config'  => [],
        ]);

        $this->assertTrue($automation->user->is($this->user));
    }

    public function test_user_has_many_automations(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'A',
            'active'  => true,
            'config'  => [],
        ]);
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'daily_agenda',
            'name'    => 'B',
            'active'  => false,
            'config'  => [],
        ]);

        $this->assertCount(2, $this->user->automations);
    }

    public function test_unique_constraint_on_user_and_type(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Original',
            'active'  => true,
            'config'  => [],
        ]);

        $this->expectException(\Illuminate\Database\QueryException::class);

        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Duplikat',
            'active'  => true,
            'config'  => [],
        ]);
    }

    public function test_different_users_can_have_same_type(): void
    {
        $otherUser = User::factory()->create();

        $a1 = Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'User 1',
            'active'  => true,
            'config'  => [],
        ]);

        $a2 = Automation::create([
            'user_id' => $otherUser->id,
            'type'    => 'event_reminder',
            'name'    => 'User 2',
            'active'  => true,
            'config'  => [],
        ]);

        $this->assertDatabaseCount('automations', 2);
        $this->assertNotEquals($a1->id, $a2->id);
    }

    // ── Livewire Component Tests ─────────────────────────────────

    public function test_automation_page_loads(): void
    {
        // User braucht role für Sidebar-Rendering (hasAtLeastRole)
        $this->user->update(['role' => 'user']);
        $response = $this->get(route('automations.index'));
        $response->assertStatus(200);
    }

    public function test_all_automation_types_are_defined(): void
    {
        $types = \App\Livewire\Automation\Index::TYPES;

        $this->assertCount(9, $types);

        $expectedTypes = [
            'event_reminder', 'daily_agenda', 'weekly_overview',
            'event_followup', 'birthday_reminder', 'no_activity_reminder',
            'daily_summary', 'contact_followup', 'free_slots_report',
        ];

        foreach ($expectedTypes as $type) {
            $this->assertArrayHasKey($type, $types);
            $this->assertArrayHasKey('name', $types[$type]);
            $this->assertArrayHasKey('description', $types[$type]);
            $this->assertArrayHasKey('icon', $types[$type]);
            $this->assertArrayHasKey('color', $types[$type]);
            $this->assertArrayHasKey('defaults', $types[$type]);
        }
    }

    public function test_toggle_creates_automation_if_not_exists(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('toggle', 'event_reminder');

        $this->assertDatabaseHas('automations', [
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'active'  => true,
        ]);
    }

    public function test_toggle_deactivates_existing_automation(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'daily_agenda',
            'name'    => 'Tägliche Agenda',
            'active'  => true,
            'config'  => ['send_time' => '08:00', 'channel' => 'email'],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('toggle', 'daily_agenda');

        $this->assertDatabaseHas('automations', [
            'user_id' => $this->user->id,
            'type'    => 'daily_agenda',
            'active'  => false,
        ]);
    }

    public function test_toggle_reactivates_inactive_automation(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'weekly_overview',
            'name'    => 'Wöchentliche Vorschau',
            'active'  => false,
            'config'  => [],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('toggle', 'weekly_overview');

        $this->assertDatabaseHas('automations', [
            'user_id' => $this->user->id,
            'type'    => 'weekly_overview',
            'active'  => true,
        ]);
    }

    public function test_save_creates_automation_with_config(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'event_reminder')
            ->set('f_minutes_before', '15')
            ->set('f_channel', 'email')
            ->call('save');

        $automation = Automation::where('user_id', $this->user->id)
            ->where('type', 'event_reminder')
            ->first();

        $this->assertNotNull($automation);
        $this->assertTrue($automation->active);
        $this->assertEquals(15, $automation->config['minutes_before']);
        $this->assertEquals('email', $automation->config['channel']);
    }

    public function test_save_updates_existing_automation(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Termin-Erinnerung',
            'active'  => true,
            'config'  => ['minutes_before' => 30, 'channel' => 'in_app'],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'event_reminder')
            ->set('f_minutes_before', '60')
            ->set('f_channel', 'email')
            ->call('save');

        $automation = Automation::where('user_id', $this->user->id)
            ->where('type', 'event_reminder')
            ->first();

        $this->assertEquals(60, $automation->config['minutes_before']);
        $this->assertEquals('email', $automation->config['channel']);
        $this->assertDatabaseCount('automations', 1);
    }

    public function test_save_ignores_invalid_type(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'nonexistent_type')
            ->call('save');

        $this->assertDatabaseCount('automations', 0);
    }

    public function test_delete_removes_automation(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Test',
            'active'  => true,
            'config'  => [],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('delete', 'event_reminder');

        $this->assertDatabaseMissing('automations', [
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
        ]);
    }

    public function test_delete_does_not_affect_other_users(): void
    {
        $otherUser = User::factory()->create();

        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Mine',
            'active'  => true,
            'config'  => [],
        ]);
        Automation::create([
            'user_id' => $otherUser->id,
            'type'    => 'event_reminder',
            'name'    => 'Others',
            'active'  => true,
            'config'  => [],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('delete', 'event_reminder');

        $this->assertDatabaseMissing('automations', [
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
        ]);
        $this->assertDatabaseHas('automations', [
            'user_id' => $otherUser->id,
            'type'    => 'event_reminder',
        ]);
    }

    public function test_open_panel_loads_defaults_for_new_automation(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('openPanel', 'event_reminder')
            ->assertSet('panelOpen', true)
            ->assertSet('activeType', 'event_reminder')
            ->assertSet('f_minutes_before', '30')
            ->assertSet('f_channel', 'in_app');
    }

    public function test_open_panel_loads_saved_config(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Termin-Erinnerung',
            'active'  => true,
            'config'  => ['minutes_before' => 45, 'channel' => 'email'],
        ]);

        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('openPanel', 'event_reminder')
            ->assertSet('f_minutes_before', '45')
            ->assertSet('f_channel', 'email');
    }

    public function test_close_panel_resets_state(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->call('openPanel', 'event_reminder')
            ->call('closePanel')
            ->assertSet('panelOpen', false)
            ->assertSet('activeType', '');
    }

    // ── Config-Builder für alle Typen ────────────────────────────

    public function test_save_daily_agenda_config(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'daily_agenda')
            ->set('f_send_time', '07:30')
            ->set('f_channel', 'email')
            ->set('f_weekdays_only', true)
            ->call('save');

        $a = Automation::where('user_id', $this->user->id)->where('type', 'daily_agenda')->first();
        $this->assertEquals('07:30', $a->config['send_time']);
        $this->assertTrue($a->config['weekdays_only']);
    }

    public function test_save_weekly_overview_config(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'weekly_overview')
            ->set('f_send_day', '5')
            ->set('f_send_time', '09:00')
            ->set('f_channel', 'email')
            ->call('save');

        $a = Automation::where('user_id', $this->user->id)->where('type', 'weekly_overview')->first();
        $this->assertEquals(5, $a->config['send_day']);
        $this->assertEquals('09:00', $a->config['send_time']);
    }

    public function test_save_event_followup_config(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'event_followup')
            ->set('f_delay_minutes', '60')
            ->set('f_create_activity', false)
            ->set('f_channel', 'email')
            ->call('save');

        $a = Automation::where('user_id', $this->user->id)->where('type', 'event_followup')->first();
        $this->assertEquals(60, $a->config['delay_minutes']);
        $this->assertFalse($a->config['create_activity']);
    }

    public function test_save_free_slots_report_config(): void
    {
        \Livewire\Livewire::test(\App\Livewire\Automation\Index::class)
            ->set('activeType', 'free_slots_report')
            ->set('f_send_day', '7')
            ->set('f_send_time', '17:00')
            ->set('f_min_slot_minutes', '90')
            ->set('f_channel', 'email')
            ->call('save');

        $a = Automation::where('user_id', $this->user->id)->where('type', 'free_slots_report')->first();
        $this->assertEquals(90, $a->config['min_slot_minutes']);
        $this->assertEquals(7, $a->config['send_day']);
    }

    // ── Cascade Delete ───────────────────────────────────────────

    public function test_automations_are_deleted_when_user_is_deleted(): void
    {
        Automation::create([
            'user_id' => $this->user->id,
            'type'    => 'event_reminder',
            'name'    => 'Test',
            'active'  => true,
            'config'  => [],
        ]);

        $this->user->forceDelete();

        $this->assertDatabaseCount('automations', 0);
    }
}
