<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use App\Models\User;
use App\Services\Event\EventRecurrence;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        /**
         *
         * admin users
         */

        // credentials from .env (with sensible fall-backs)
        $email     = env('ADMIN_EMAIL',     'admin@example.com');
        $password  = env('ADMIN_PASSWORD',  'changeme');
        $firstname = env('ADMIN_FIRSTNAME', 'Admin');
        $lastname  = env('ADMIN_LASTNAME',  'Account');
        $timezone  = env('APP_TIMEZONE',    'UTC');

        // create or update the admin user
        $user = User::updateOrCreate(
            ['email' => $email],
            [
                'firstname'   => $firstname,
                'lastname'    => $lastname,
                'timezone'    => $timezone,
                'password'    => Hash::make($password),
            ]
        );

        // fill the sabre-friendly columns
        $user->update([
            'uri'         => 'principals/'.$user->email,
            'displayname' => $firstname.' '.$lastname,
        ]);

        /**
         *
         * global calendar settings (user_settings)
         */

        $defaultCalendarSettings = [
            'app.language'    => 'en',
            'app.region'      => 'US',
            'app.date_format' => 'mdy',
            'app.time_format' => '12',
        ];

        foreach ($defaultCalendarSettings as $key => $value) {
            DB::table('user_settings')->updateOrInsert(
                [
                    'user_id' => $user->id,
                    'key' => $key,
                ],
                [
                    'value' => (string) $value,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );
        }

        /**
         *
         * calendar and meta
         */

        // sample caldav data
        $calId = DB::table('calendars')->insertGetId([
            'synctoken'   => 1,
            'components'  => 'VEVENT',
        ]);

        $instanceId = DB::table('calendarinstances')->insertGetId([
            'calendarid'    => $calId,
            'principaluri'  => $user->uri,          // uses new column
            'uri'           => Str::uuid(),
            'displayname'   => 'Sample Calendar',
            'description'   => 'Seeded calendar',
            'calendarorder' => 0,
            'calendarcolor' => '#0038ff',
            'timezone'      => $timezone,
        ]);

        DB::table('calendar_meta')->updateOrInsert(
            ['calendar_id' => $calId], // @todo should this be calendar id or instance id?
            ['color' => '#0038ff']
        );

        /**
         *
         * create the locations connected to each event
         **/

        // locations
        $locationSeeds = [
            'Home'  => [       // free-text, no geo
                'display' => 'Home',
                'raw'     => null,
            ],
            'Living Room' => [
                'display' => 'Living Room',
                'raw'     => null,
            ],
            'McCahill Park' => [
                'display' => 'McCahill Park',
                'raw'     => '625 Hemlock Hollow Rd, Pittsburgh, PA 15238',
            ],
            'Meadow Park' => [
                'display' => 'Meadow Park',
                'raw'     => '2 Meadow Park Lane, Pittsburgh, PA 15215',
            ],
            'AHN Pediatrics' => [
                'display' => 'AHN Pediatrics',
                'raw'     => '3394 Saxonburg Blvd Suite 600, Glenshaw, PA 15116',
            ],
            'The Discovery School' => [
                'display' => 'The Discovery School',
                'raw'     => '4225 Middle Rd, Allison Park, PA 15101',
            ],
            'Fairview Elementary School' => [
                'display' => 'Fairview Elementary School',
                'raw'     => '738 Dorseyville Rd, Pittsburgh, PA 15238',
            ],
        ];

        // create the locations first
        $locationIdMap = [];
        foreach ($locationSeeds as $key => $data) {
            $locId = DB::table('locations')->updateOrInsert(
                ['display_name' => $data['display']],           // uniqueness key
                [
                    'raw_address' => $data['raw'],
                    'created_at'  => now(),
                    'updated_at'  => now(),
                ]
            );

            // updateOrInsert returns boolean; fetch id explicitly
            $locId = DB::table('locations')->where('display_name', $data['display'])->value('id');
            $locationIdMap[$key] = $locId;
        }

        /**
         *
         * cevent creation helper function
         **/

        $insertEvent = function (Carbon $start, string $summary, string $locationKey) use ($calId, $locationIdMap, $locationSeeds)
        {
            // base vars (start is in your "authoring" timezone, e.g. America/New_York)
            $uid = Str::uuid().'@kithkin.lan';
            $end = $start->copy()->addHour();

            // normalize once: everything stored is UTC
            $startUtc = $start->copy()->utc();
            $endUtc   = $end->copy()->utc();

            // ICS fields should be UTC with Z
            $dtstamp = $startUtc->format('Ymd\\THis\\Z');
            $dtstart = $startUtc->format('Ymd\\THis\\Z');
            $dtend   = $endUtc->format('Ymd\\THis\\Z');

            $locationDisplay = $locationKey;
            $locationRaw     = $locationSeeds[$locationKey]['raw'] ?? null;
            $icalLocation    = $locationRaw ?? $locationDisplay;

            $ical = <<<ICS
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Kithkin//Laravel CalDAV//EN
BEGIN:VEVENT
UID:$uid
DTSTAMP:$dtstamp
DTSTART:$dtstart
DTEND:$dtend
SUMMARY:$summary
DESCRIPTION:Automatically seeded event
LOCATION:$icalLocation
END:VEVENT
END:VCALENDAR
ICS;

            $eventId = DB::table('calendarobjects')->insertGetId([
                'calendarid'    => $calId,
                'uri'           => Str::uuid().'.ics',
                'lastmodified'  => time(),
                'etag'          => md5($ical),
                'size'          => strlen($ical),
                'componenttype' => 'VEVENT',
                'uid'           => $uid,
                'calendardata'  => $ical,
            ]);

            DB::table('event_meta')->updateOrInsert(
                ['event_id' => $eventId],
                [
                    'title'       => $summary,
                    'description' => 'Automatically seeded event',
                    'location'    => $locationRaw ? null : $locationDisplay,
                    'location_id' => $locationIdMap[$locationKey] ?? null,
                    'all_day'     => false,
                    'category'    => 'Demo',
                    'start_at'    => $startUtc,
                    'end_at'      => $endUtc,
                    'created_at'  => now(),
                    'updated_at'  => now(),
                ]
            );
        };

        $recurrence = new EventRecurrence();

        $insertRecurringEvent = function (
            Carbon $start,
            string $summary,
            string $locationKey,
            string $rrule,
            string $tz
        ) use ($calId, $locationIdMap, $locationSeeds, $recurrence) {
            $uid = Str::uuid().'@'.parse_url(config('app.url'), PHP_URL_HOST);
            $end = $start->copy()->addHour();

            $startUtc = $start->copy()->utc();
            $endUtc   = $end->copy()->utc();

            $locationDisplay = $locationKey;
            $locationRaw     = $locationSeeds[$locationKey]['raw'] ?? null;
            $icalLocation    = $locationRaw ?? $locationDisplay;

            $ical = $recurrence->buildCalendar([
                'uid'         => $uid,
                'start_utc'   => $startUtc,
                'end_utc'     => $endUtc,
                'summary'     => $summary,
                'description' => 'Automatically seeded recurring event',
                'location'    => $icalLocation,
                'tzid'        => $tz,
                'rrule'       => $rrule,
            ]);

            $eventId = DB::table('calendarobjects')->insertGetId([
                'calendarid'    => $calId,
                'uri'           => Str::uuid().'.ics',
                'lastmodified'  => time(),
                'etag'          => md5($ical),
                'size'          => strlen($ical),
                'componenttype' => 'VEVENT',
                'uid'           => $uid,
                'calendardata'  => $ical,
            ]);

            DB::table('event_meta')->updateOrInsert(
                ['event_id' => $eventId],
                [
                    'title'       => $summary,
                    'description' => 'Automatically seeded recurring event',
                    'location'    => $locationRaw ? null : $locationDisplay,
                    'location_id' => $locationIdMap[$locationKey] ?? null,
                    'all_day'     => false,
                    'category'    => 'Demo',
                    'start_at'    => $startUtc,
                    'end_at'      => $endUtc,
                    'extra'       => json_encode([
                        'rrule' => $rrule,
                        'tzid'  => $tz,
                    ]),
                    'created_at'  => now(),
                    'updated_at'  => now(),
                ]
            );
        };

        /**
         *
         * create events
         */

        $tz = 'America/New_York';
        $now = Carbon::now($tz)->setSeconds(0);

        // 3 events today
        $insertEvent($now->copy(), 'Playground with James', 'McCahill Park');
        $insertEvent($now->copy()->addHours(2), 'Lunch with Daniel', 'Home');
        $insertEvent($now->copy()->addHours(4), 'Baseball practice', 'Meadow Park');

        // 1 event 3 days ago
        $past = $now->copy()->subDays(3)->setTime(10, 0);
        $insertEvent($past, 'Kids doctors appointments', 'AHN Pediatrics');

        // 1 event 2 days ahead
        $future2 = $now->copy()->addDays(2)->setTime(14, 0);
        $insertEvent($future2, 'Teacher conference (Nuthatches)', 'The Discovery School');

        // 2 events 5 days ahead
        $future5a = $now->copy()->addDays(5)->setTime(9, 0);
        $future5b = $future5a->copy()->addHours(2);
        $insertEvent($future5a, 'Teacher conference (3rd grade)', 'Fairview Elementary');
        $insertEvent($future5b, 'Family game night', 'Living Room');

        // overlapping events 3 days after "now"
        $overlapDay = $now->copy()->addDays(3)->setTime(9, 0);
        $insertEvent($overlapDay->copy(), 'Overlap: Daily standup', 'Home');
        $insertEvent($overlapDay->copy()->addMinutes(15), 'Overlap: Design review', 'Living Room');
        $insertEvent($overlapDay->copy()->addMinutes(30), 'Overlap: Vendor call', 'McCahill Park');
        $insertEvent($overlapDay->copy()->addMinutes(45), 'Overlap: Planning session', 'Meadow Park');

        // recurring: weekly on Mon/Wed for 8 weeks at 6:30pm
        $recurringStart = $now->copy()->next(Carbon::MONDAY)->setTime(18, 30);
        $insertRecurringEvent(
            $recurringStart,
            'Evening run',
            'McCahill Park',
            'FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16',
            $tz
        );

        /**
         *
         * address books
         *
         */

        // create cards
        $bookId = DB::table('addressbooks')->insertGetId([
            'principaluri' => $user->uri,
            'uri'          => 'default',
            'displayname'  => 'Default Address Book',
        ]);

        $vcard = <<<VCF
BEGIN:VCARD
VERSION:3.0
FN:Seeded Contact
EMAIL:seeded@example.com
TEL:+1-555-123-4567
UID:seeded-contact-001
END:VCARD
VCF;

        DB::table('addressbook_meta')->insert([
            'addressbook_id' => $bookId,
            'color'          => '#ff40ff',
            'is_default'     => true,
            'settings'       => null,
            'created_at'     => now(),
            'updated_at'     => now(),
        ]);

        $cardId = DB::table('cards')->insertGetId([
            'addressbookid' => $bookId,
            'uri'           => Str::uuid().'.vcf',
            'lastmodified'  => now()->timestamp,
            'etag'          => md5($vcard),
            'size'          => strlen($vcard),
            'carddata'      => $vcard,
        ]);

        DB::table('contact_meta')->insert([
            'card_id'    => $cardId,
            'avatar_url' => null,
            'tags'       => 'demo,seed',
            'notes'      => 'Seeded contact from DatabaseSeeder.',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

    }
}
