<?php

namespace Modules\MedWorkforce\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedWorkforce\Entities\CredentialReview;
use Modules\MedWorkforce\Entities\RosterAssignment;
use Modules\MedWorkforce\Entities\ShiftTemplate;
use Modules\MedWorkforce\Entities\SwapRequest;

/**
 * Demo data for the business named 'Shifa One' only. Unlike a silent skip, this
 * seeder WARNS (not silent) when the host is not Shifa or the demo staff are
 * absent, so a mis-seeded environment is visible in the install log.
 *
 * Seeds (idempotent — updateOrCreate/firstOrCreate on natural keys):
 *   - 4 shift templates: Morning, Evening, Night, On-call.
 *   - a week of roster assignments for the existing *.shifa staff across the
 *     hospital + clinic locations (Morning for day staff, Night rotated in).
 *   - 1 pending swap request between two doctors.
 *   - a couple of credential_reviews (a completed mandatory training + an
 *     overdue competency) overlaying MedOrganization's licence data.
 *
 * Never invents ERP users/locations — it only references existing demo rows.
 * All cross-module reads are fail-soft.
 */
class MedwfDemoSeeder extends Seeder
{
    public function run(): void
    {
        if (! Schema::hasTable('business') || ! Schema::hasTable('medwf_shift_templates')) {
            $this->report('MedWorkforce demo: core/module tables missing — skipped.');

            return;
        }

        $business = DB::table('business')->where('name', 'Shifa One')->first();
        if (empty($business)) {
            $this->report('MedWorkforce demo: business "Shifa One" not found — skipped (this is expected off the Shifa demo host).');

            return;
        }

        $businessId = (int) $business->id;

        // ── Resolve the demo staff (usernames match MedOrganization's demo) ──
        $usernames = [
            'dr.yasmin.shifa', 'dr.omar.shifa', 'nurse.shifa',
            'reception.shifa', 'pharmacist.shifa', 'accountant.shifa',
        ];
        $userIds = DB::table('users')
            ->where('business_id', $businessId)
            ->whereIn('username', $usernames)
            ->pluck('id', 'username');

        if ($userIds->isEmpty()) {
            $this->report('MedWorkforce demo: no *.shifa staff users found — seeding templates only.');
        }

        // ── Locations (hospital + clinic) ───────────────────────────────────
        $locations = $this->locations($businessId);

        // ── Departments (Cardiology / General Surgery) ──────────────────────
        $departments = $this->departments($businessId);

        // ── 4 shift templates ───────────────────────────────────────────────
        $templates = $this->templates($businessId, $locations, $departments);

        // ── A week of roster assignments ────────────────────────────────────
        $created = $this->roster($businessId, $userIds->toArray(), $templates, $locations, $departments);

        // ── 1 pending swap ──────────────────────────────────────────────────
        $this->pendingSwap($businessId, $userIds->toArray());

        // ── A couple of credential reviews ──────────────────────────────────
        $this->credentialReviews($businessId, $userIds->toArray());

        $this->report('MedWorkforce demo: ' . count($templates) . ' templates, ' . $created
            . ' roster cell(s), 1 pending swap and credential reviews seeded for "Shifa One".');
    }

    /** @return array<string,int> key => business_location_id */
    protected function locations(int $businessId): array
    {
        $out = [];
        if (! Schema::hasTable('business_locations')) {
            return $out;
        }

        $rows = DB::table('business_locations')
            ->where('business_id', $businessId)
            ->whereNull('deleted_at')
            ->pluck('id', 'name');

        foreach (['hospital' => 'Hospital', 'clinic' => 'Clinic'] as $key => $needle) {
            foreach ($rows as $name => $id) {
                if (stripos((string) $name, $needle) !== false) {
                    $out[$key] = (int) $id;
                    break;
                }
            }
        }

        return $out;
    }

    /** @return array<string,int> name => clc_departments id */
    protected function departments(int $businessId): array
    {
        $out = [];
        if (! Schema::hasTable('clc_departments')) {
            return $out;
        }

        foreach (['Cardiology', 'General Surgery'] as $name) {
            $id = DB::table('clc_departments')
                ->where('business_id', $businessId)
                ->where('name', $name)
                ->value('id');
            if ($id) {
                $out[$name] = (int) $id;
            }
        }

        return $out;
    }

    /**
     * @param  array<string,int>  $locations
     * @param  array<string,int>  $departments
     * @return ShiftTemplate[]
     */
    protected function templates(int $businessId, array $locations, array $departments): array
    {
        $plan = [
            ['name' => 'Morning', 'start' => '08:00', 'end' => '16:00', 'color' => '#00a65a', 'night' => false, 'break' => 30],
            ['name' => 'Evening', 'start' => '16:00', 'end' => '00:00', 'color' => '#f39c12', 'night' => false, 'break' => 30],
            ['name' => 'Night',   'start' => '00:00', 'end' => '08:00', 'color' => '#605ca8', 'night' => true,  'break' => 45],
            ['name' => 'On-call', 'start' => '08:00', 'end' => '08:00', 'color' => '#dd4b39', 'night' => true,  'break' => 0],
        ];

        $out = [];
        foreach ($plan as $p) {
            $out[$p['name']] = ShiftTemplate::updateOrCreate(
                ['business_id' => $businessId, 'name' => $p['name']],
                [
                    'start_time'           => $p['start'],
                    'end_time'             => $p['end'],
                    'department_id'        => null,
                    'business_location_id' => $locations['hospital'] ?? null,
                    'break_minutes'        => $p['break'],
                    'night_allowance'      => $p['night'],
                    'color'                => $p['color'],
                    'is_active'            => true,
                ]
            );
        }

        return $out;
    }

    /**
     * A week of assignments starting this Monday. Day staff get Morning; the
     * nurse rotates onto Night mid-week. Idempotent per (business,user,date,tmpl).
     *
     * @param  array<string,int>  $userIds     username => id
     * @param  array<string,ShiftTemplate>  $templates
     * @param  array<string,int>  $locations
     * @param  array<string,int>  $departments
     */
    protected function roster(int $businessId, array $userIds, array $templates, array $locations, array $departments): int
    {
        if (empty($userIds) || empty($templates)) {
            return 0;
        }

        $monday = Carbon::today()->startOfWeek(Carbon::MONDAY);
        $hospital = $locations['hospital'] ?? null;
        $clinic = $locations['clinic'] ?? null;

        // Who works which template, and where.
        $plan = [
            'dr.yasmin.shifa'  => ['tmpl' => 'Morning', 'loc' => $hospital, 'dept' => $departments['Cardiology'] ?? null],
            'dr.omar.shifa'    => ['tmpl' => 'Morning', 'loc' => $hospital, 'dept' => $departments['General Surgery'] ?? null],
            'nurse.shifa'      => ['tmpl' => 'Morning', 'loc' => $hospital, 'dept' => $departments['Cardiology'] ?? null],
            'reception.shifa'  => ['tmpl' => 'Morning', 'loc' => $clinic,   'dept' => null],
            'pharmacist.shifa' => ['tmpl' => 'Evening', 'loc' => $clinic,   'dept' => null],
        ];

        $count = 0;
        foreach ($plan as $username => $spec) {
            if (empty($userIds[$username]) || empty($templates[$spec['tmpl']])) {
                continue;
            }
            $userId = (int) $userIds[$username];

            for ($i = 0; $i < 5; $i++) { // Mon–Fri
                $date = $monday->copy()->addDays($i)->toDateString();

                // The nurse rotates to Night on Thu/Fri.
                $tmplKey = ($username === 'nurse.shifa' && $i >= 3) ? 'Night' : $spec['tmpl'];
                $template = $templates[$tmplKey] ?? $templates[$spec['tmpl']];

                RosterAssignment::updateOrCreate(
                    [
                        'business_id'       => $businessId,
                        'user_id'           => $userId,
                        'date'              => $date,
                        'shift_template_id' => $template->id,
                    ],
                    [
                        'department_id'        => $spec['dept'],
                        'business_location_id' => $spec['loc'],
                        'status'               => 'scheduled',
                        'created_by'           => null,
                    ]
                );
                $count++;
            }
        }

        return $count;
    }

    /** One pending swap: Yasmin asks Omar to take her Monday shift. */
    protected function pendingSwap(int $businessId, array $userIds): void
    {
        if (empty($userIds['dr.yasmin.shifa']) || empty($userIds['dr.omar.shifa'])) {
            return;
        }

        $monday = Carbon::today()->startOfWeek(Carbon::MONDAY)->toDateString();

        $assignment = RosterAssignment::forBusiness($businessId)
            ->where('user_id', $userIds['dr.yasmin.shifa'])
            ->whereDate('date', $monday)
            ->orderBy('id')
            ->first();

        if (! $assignment) {
            return;
        }

        SwapRequest::firstOrCreate(
            [
                'business_id'          => $businessId,
                'roster_assignment_id' => $assignment->id,
                'requested_by'         => $userIds['dr.yasmin.shifa'],
                'status'               => 'pending',
            ],
            [
                'requested_with_user_id' => $userIds['dr.omar.shifa'],
                'reason'                 => 'Demo: conference on Monday morning.',
            ]
        );
    }

    /** A completed mandatory training + an overdue competency review. */
    protected function credentialReviews(int $businessId, array $userIds): void
    {
        if (! empty($userIds['nurse.shifa'])) {
            CredentialReview::updateOrCreate(
                [
                    'business_id' => $businessId,
                    'user_id'     => $userIds['nurse.shifa'],
                    'item_type'   => 'mandatory_training',
                    'title'       => 'Basic Life Support (BLS) refresher',
                ],
                [
                    'due_date'       => Carbon::today()->addMonths(3)->toDateString(),
                    'completed_date' => Carbon::today()->subDays(10)->toDateString(),
                    'status'         => 'completed',
                    'notes'          => 'Demo: annual BLS completed.',
                ]
            );
        }

        if (! empty($userIds['dr.omar.shifa'])) {
            CredentialReview::updateOrCreate(
                [
                    'business_id' => $businessId,
                    'user_id'     => $userIds['dr.omar.shifa'],
                    'item_type'   => 'competency',
                    'title'       => 'Laparoscopic competency sign-off',
                ],
                [
                    'due_date'       => Carbon::today()->subDays(5)->toDateString(), // past due -> overdue
                    'completed_date' => null,
                    'status'         => 'pending',
                    'notes'          => 'Demo: overdue competency review — exercises the overdue badge.',
                ]
            );
        }
    }

    private function report(string $msg): void
    {
        if ($this->command) {
            $this->command->info($msg);
        }
    }
}
