<?php

namespace Modules\MedOrganization\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedOrganization\Entities\OrgFacilityProfile;
use Modules\MedOrganization\Entities\OrgRoom;
use Modules\MedOrganization\Entities\OrgStaffLicense;
use Modules\MedOrganization\Entities\OrgUserDepartment;

/**
 * Demo data for the 'Shifa One' demo business (created by
 * database/seeders/ShifaInstallSeeder). Does NOTHING when that business is
 * absent. Fully idempotent (updateOrCreate everywhere).
 */
class OrgDemoSeeder extends Seeder
{
    protected int $businessId;

    public function run(): void
    {
        $business = DB::table('business')->where('name', 'Shifa One')->first();
        if (! $business) {
            return; // guard: demo business not installed
        }
        if (! Schema::hasTable('clc_departments')) {
            return; // ClinicCore not migrated — departments/rooms need it
        }

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

        $locations = $this->facilityProfiles();
        $departments = $this->departments($locations);
        $this->rooms($departments);
        $userIds = $this->staffAssignments($departments);
        $this->mapUsersToRoles($userIds);
        $this->licenses($userIds);

        if (isset($this->command)) {
            $this->command->info('MedOrganization demo data seeded for Shifa One (business #' . $this->businessId . ').');
        }
    }

    /**
     * Facility profiles for the existing Shifa One locations.
     *
     * @return array<string, int> key => business_location_id
     */
    protected function facilityProfiles(): array
    {
        $rows = DB::table('business_locations')
            ->where('business_id', $this->businessId)
            ->whereNull('deleted_at')
            ->pluck('id', 'name');

        $find = function (string $needle) use ($rows): ?int {
            foreach ($rows as $name => $id) {
                if (stripos($name, $needle) !== false) {
                    return (int) $id;
                }
            }

            return null;
        };

        $hours = [
            'mon' => ['08:00-20:00'], 'tue' => ['08:00-20:00'], 'wed' => ['08:00-20:00'],
            'thu' => ['08:00-20:00'], 'fri' => ['10:00-18:00'], 'sat' => ['08:00-20:00'],
            'sun' => ['08:00-20:00'],
        ];

        $plan = [
            'hospital' => ['locate' => 'Hospital', 'code' => 'HOSP-MAIN', 'type' => 'hospital',
                'capacity' => ['beds' => 120, 'daily_outpatient' => 400, 'daily_lab_samples' => 250, 'daily_imaging' => 80],
                'geo' => [30.0300000, 31.4700000]],
            'clinic' => ['locate' => 'Clinic', 'code' => 'CLIN-MAADI', 'type' => 'clinic',
                'capacity' => ['beds' => null, 'daily_outpatient' => 120, 'daily_lab_samples' => 40, 'daily_imaging' => 10],
                'geo' => [29.9600000, 31.2600000]],
            'pharmacy' => ['locate' => 'Pharmacy', 'code' => 'PHARM-STORE', 'type' => 'pharmacy',
                'capacity' => ['beds' => null, 'daily_outpatient' => null, 'daily_lab_samples' => null, 'daily_imaging' => null],
                'geo' => [30.0200000, 31.4900000]],
        ];

        $ids = [];
        $hospitalId = $find($plan['hospital']['locate']);

        foreach ($plan as $key => $p) {
            $locationId = $find($p['locate']);
            if (! $locationId) {
                continue; // location renamed/removed — skip quietly
            }
            $ids[$key] = $locationId;

            OrgFacilityProfile::updateOrCreate(
                ['business_location_id' => $locationId],
                [
                    'business_id'        => $this->businessId,
                    'code'               => $p['code'],
                    'facility_type'      => $p['type'],
                    // Clinic + store hang under the main hospital (depth 2 ≤ 5).
                    'parent_location_id' => ($key !== 'hospital' && $hospitalId && $hospitalId !== $locationId) ? $hospitalId : null,
                    'working_hours'      => $hours,
                    'capacity'           => $p['capacity'],
                    'geo_lat'            => $p['geo'][0],
                    'geo_lng'            => $p['geo'][1],
                    'status'             => 'active',
                ]
            );
        }

        return $ids;
    }

    /**
     * Departments with the new org fields (updateOrCreate on business+name so
     * departments created by ShifaInstallSeeder are enriched, not duplicated).
     *
     * @param  array<string, int>  $locations
     * @return array<string, int> name => clc_departments id
     */
    protected function departments(array $locations): array
    {
        $hours = [
            'mon' => ['09:00-17:00'], 'tue' => ['09:00-17:00'], 'wed' => ['09:00-17:00'],
            'thu' => ['09:00-17:00'], 'sat' => ['09:00-17:00'], 'sun' => ['09:00-17:00'],
        ];

        $plan = [
            ['name' => 'Cardiology',      'code' => 'CARD', 'dept_type' => 'clinical',       'location' => 'hospital', 'sort_order' => 1],
            ['name' => 'General Surgery', 'code' => 'SURG', 'dept_type' => 'clinical',       'location' => 'hospital', 'sort_order' => 2],
            ['name' => 'Radiology',       'code' => 'RAD',  'dept_type' => 'diagnostic',     'location' => 'hospital', 'sort_order' => 3],
            ['name' => 'Administration',  'code' => 'ADMIN', 'dept_type' => 'administrative', 'location' => 'clinic',   'sort_order' => 9],
        ];

        $hasNewCols = Schema::hasColumn('clc_departments', 'dept_type');

        $ids = [];
        foreach ($plan as $d) {
            $attributes = ['status' => 'active'];
            if ($hasNewCols) {
                $attributes += [
                    'code'                 => $d['code'],
                    'dept_type'            => $d['dept_type'],
                    'working_hours'        => json_encode($hours),
                    'business_location_id' => $locations[$d['location']] ?? null,
                    'sort_order'           => $d['sort_order'],
                ];
            }

            $dept = \Modules\ClinicCore\Entities\ClcDepartment::updateOrCreate(
                ['business_id' => $this->businessId, 'name' => $d['name']],
                $attributes
            );
            $ids[$d['name']] = (int) $dept->id;
        }

        return $ids;
    }

    /** A few rooms per department. */
    protected function rooms(array $departments): void
    {
        $plan = [
            'Cardiology' => [
                ['name' => 'Cardio Consultation 1', 'code' => 'CARD-C1', 'room_type' => 'consultation', 'floor' => 2, 'capacity' => 2, 'scheduling_enabled' => true],
                ['name' => 'Cardio Consultation 2', 'code' => 'CARD-C2', 'room_type' => 'consultation', 'floor' => 2, 'capacity' => 2, 'scheduling_enabled' => true],
                ['name' => 'Echo Lab',              'code' => 'CARD-ECHO', 'room_type' => 'imaging', 'floor' => 2, 'capacity' => 1, 'equipment' => ['echocardiograph'], 'scheduling_enabled' => true],
            ],
            'General Surgery' => [
                ['name' => 'OR 1',            'code' => 'SURG-OR1', 'room_type' => 'operating', 'floor' => 3, 'capacity' => 8, 'equipment' => ['anesthesia machine', 'surgical lights'], 'scheduling_enabled' => true],
                ['name' => 'Surgery Consult', 'code' => 'SURG-C1', 'room_type' => 'consultation', 'floor' => 3, 'capacity' => 2, 'scheduling_enabled' => true],
            ],
            'Radiology' => [
                ['name' => 'X-Ray Room',   'code' => 'RAD-XR1', 'room_type' => 'imaging', 'floor' => 1, 'capacity' => 1, 'equipment' => ['x-ray unit'], 'scheduling_enabled' => true],
                ['name' => 'Waiting Area', 'code' => 'RAD-W1', 'room_type' => 'waiting', 'floor' => 1, 'capacity' => 12],
            ],
            'Administration' => [
                ['name' => 'Records Office', 'code' => 'ADM-REC', 'room_type' => 'admin', 'floor' => 1, 'capacity' => 4],
            ],
        ];

        foreach ($plan as $deptName => $rooms) {
            if (empty($departments[$deptName])) {
                continue;
            }
            foreach ($rooms as $room) {
                OrgRoom::updateOrCreate(
                    [
                        'business_id'   => $this->businessId,
                        'department_id' => $departments[$deptName],
                        'code'          => $room['code'],
                    ],
                    $room + ['status' => 'available']
                );
            }
        }
    }

    /**
     * Assign the existing Shifa staff users to departments.
     *
     * @return array<string, int> username => user id
     */
    protected function staffAssignments(array $departments): array
    {
        $usernames = [
            'dr.yasmin.shifa'  => ['Cardiology', true],
            'dr.omar.shifa'    => ['General Surgery', true],
            'nurse.shifa'      => ['Cardiology', true],
            'reception.shifa'  => ['Administration', true],
            'accountant.shifa' => ['Administration', false],
            'pharmacist.shifa' => ['Administration', false],
        ];

        $userIds = [];
        foreach ($usernames as $username => [$deptName, $isPrimary]) {
            $user = DB::table('users')
                ->where('username', $username)
                ->where('business_id', $this->businessId)
                ->first();
            if (! $user || empty($departments[$deptName])) {
                continue;
            }
            $userIds[$username] = (int) $user->id;

            OrgUserDepartment::updateOrCreate(
                ['user_id' => $user->id, 'department_id' => $departments[$deptName]],
                ['business_id' => $this->businessId, 'is_primary' => $isPrimary]
            );
        }

        // Department heads: the two doctors head their own departments.
        if (Schema::hasColumn('clc_departments', 'head_user_id')) {
            $heads = [
                'Cardiology'      => $userIds['dr.yasmin.shifa'] ?? null,
                'General Surgery' => $userIds['dr.omar.shifa'] ?? null,
            ];
            foreach ($heads as $deptName => $userId) {
                if ($userId && ! empty($departments[$deptName])) {
                    DB::table('clc_departments')->where('id', $departments[$deptName])
                        ->update(['head_user_id' => $userId]);
                }
            }
        }

        return $userIds;
    }

    /**
     * Map the demo users to the new predefined roles IN ADDITION to their
     * current roles (TENANCY-PERMISSIONS-AUDIT §3.5 — nothing is revoked).
     */
    protected function mapUsersToRoles(array $userIds): void
    {
        $map = [
            'dr.yasmin.shifa'  => 'doctor',
            'dr.omar.shifa'    => 'doctor',
            'nurse.shifa'      => 'nurse',
            'reception.shifa'  => 'receptionist',
            'pharmacist.shifa' => 'pharmacist',
            'accountant.shifa' => 'accountant',
        ];

        foreach ($map as $username => $roleKey) {
            if (empty($userIds[$username])) {
                continue;
            }
            $roleName = $roleKey . '#' . $this->businessId;
            try {
                $user = \App\User::find($userIds[$username]);
                if ($user && ! $user->hasRole($roleName)) {
                    $user->assignRole($roleName);
                }
            } catch (\Throwable $e) {
                \Log::warning('MedOrganization demo: could not assign role ' . $roleName . ' to ' . $username . ': ' . $e->getMessage());
            }
        }
    }

    /** Two sample licenses: one verified, one expiring soon (alert demo). */
    protected function licenses(array $userIds): void
    {
        $ownerId = optional(DB::table('business')->where('id', $this->businessId)->first())->owner_id;

        if (! empty($userIds['dr.yasmin.shifa'])) {
            OrgStaffLicense::updateOrCreate(
                [
                    'business_id'    => $this->businessId,
                    'user_id'        => $userIds['dr.yasmin.shifa'],
                    'license_type'   => 'medical_license',
                    'license_number' => 'EG-MED-114455',
                ],
                [
                    'issuing_authority' => 'Egyptian Medical Syndicate',
                    'issue_date'        => now()->subYears(3)->toDateString(),
                    'expiry_date'       => now()->addYears(2)->toDateString(),
                    'specialization'    => 'Cardiology',
                    'status'            => 'verified',
                    'verified_by'       => $ownerId,
                    'verified_at'       => now()->subMonth(),
                    'notes'             => 'Demo: verified license.',
                ]
            );
        }

        if (! empty($userIds['dr.omar.shifa'])) {
            OrgStaffLicense::updateOrCreate(
                [
                    'business_id'    => $this->businessId,
                    'user_id'        => $userIds['dr.omar.shifa'],
                    'license_type'   => 'specialization_cert',
                    'license_number' => 'EG-SURG-77821',
                ],
                [
                    'issuing_authority' => 'Egyptian Board of Surgery',
                    'issue_date'        => now()->subYears(5)->toDateString(),
                    'expiry_date'       => now()->addDays(20)->toDateString(), // triggers the 30-day expiry alert
                    'specialization'    => 'General Surgery',
                    'status'            => 'pending_verification',
                    'notes'             => 'Demo: expiring soon — exercise the alert cron.',
                ]
            );
        }
    }
}
