<?php

namespace App\Database\Seeds;

use CodeIgniter\Database\Seeder;
use CodeIgniter\Database\BaseConnection;

class FamiliesBootstrapSeeder extends Seeder
{
    /** @var BaseConnection */
    protected $db;

    // Map your legacy `parents` table/columns
    protected array $legacy = [
        'table'          => 'parents',                 // legacy table
        'firstparent_id' => 'firstparent_id',          // users.id (primary parent)
        'second_user_id' => 'secondparent_id',         // users.id of 2nd parent if present (may be 0)
        'email'          => 'secondparent_email',
        'firstname'      => 'secondparent_firstname',
        'lastname'       => 'secondparent_lastname',
    ];

    public function run()
    {
        $this->db = \Config\Database::connect();

        // While tuning, you can comment these two lines to avoid full rollback
        $this->db->transStart();

        [$familiesCreated, $studentsLinked, $primGuardiansLinked] = $this->bootstrapByPrimaryParents();
        [$createdUsers, $secGuardiansLinked, $skippedLegacy, $legacyTotal] = $this->importLegacySecondParents();

        $this->db->transComplete();

        echo PHP_EOL;
        echo "Families created:       {$familiesCreated}\n";
        echo "Students linked:        {$studentsLinked}\n";
        echo "Primary guardians:      {$primGuardiansLinked}\n";
        echo "Legacy rows scanned:    {$legacyTotal}\n";
        echo "Stub users created:     {$createdUsers}\n";
        echo "Secondary guardians:    {$secGuardiansLinked}\n";
        echo "Legacy rows skipped:    {$skippedLegacy}\n";
        echo PHP_EOL;
    }

    /** Create/ensure one family per primary parent (students.parent_id), link students, add primary guardian. */
    protected function bootstrapByPrimaryParents(): array
    {
        $familiesCreated = 0; $studentsLinked = 0; $primGuardiansLinked = 0;

        $primaryParents = $this->db->query(
            "SELECT DISTINCT parent_id FROM students WHERE parent_id IS NOT NULL"
        )->getResultArray();

        foreach ($primaryParents as $row) {
            $primaryUserId = (int) $row['parent_id'];
            if ($primaryUserId <= 0) { continue; }

            $familyId = $this->ensureFamilyForPrimaryParent($primaryUserId, $familiesCreated);

            // link all kids of this primary parent
            $kids = $this->db->query("SELECT id FROM students WHERE parent_id = ?", [$primaryUserId])->getResultArray();
            foreach ($kids as $s) {
                $studentsLinked += $this->attachStudentToFamily((int)$s['id'], $familyId);
            }

            // ensure primary guardian link
            $primGuardiansLinked += $this->attachGuardianUser($familyId, $primaryUserId, 'primary', 1, 1, 0);
        }

        return [$familiesCreated, $studentsLinked, $primGuardiansLinked];
    }

    /** Import second parents from legacy `parents` table (by email or secondparent_id). */
    protected function importLegacySecondParents(): array
    {
        $L = $this->legacy;
        $createdUsers = 0; $linked = 0; $skipped = 0; $total = 0;

        if (! $this->db->tableExists($L['table'])) {
            echo "[LEGACY] Table '{$L['table']}' not found; skipping.\n";
            return [0,0,0,0];
        }

        $fields = array_map('strtolower', array_column($this->db->getFieldData($L['table']), 'name'));
        foreach (['firstparent_id','email','firstname','lastname','second_user_id'] as $k) {
            if (! array_key_exists($k, $L)) continue;
            $col = strtolower($L[$k]);
            if ($col && ! in_array($col, $fields, true)) {
                echo "[LEGACY] Missing column {$L[$k]} in {$L['table']}; skipping import.\n";
                return [0,0,0,0];
            }
        }

        $qb = $this->db->table($L['table']);
        $qb->select("{$L['firstparent_id']} AS firstparent_id", false)
           ->select("{$L['second_user_id']} AS secondparent_id", false)
           ->select("{$L['email']} AS email", false)
           ->select("{$L['firstname']} AS firstname", false)
           ->select("{$L['lastname']} AS lastname", false)
           ->where("{$L['email']} IS NOT NULL", null, false)
           ->where("{$L['email']} !=", '');

        $q = $qb->get();
        if ($q === false) {
            $err = $this->db->error();
            echo "[LEGACY] Query failed: {$err['code']} {$err['message']}\n";
            return [0,0,0,0];
        }

        $rows = $q->getResultArray();
        $total = count($rows);

        foreach ($rows as $r) {
            $primaryUserId = (int)($r['firstparent_id'] ?? 0);
            $email         = trim((string)($r['email'] ?? ''));
            $first         = trim((string)($r['firstname'] ?? ''));
            $last          = trim((string)($r['lastname'] ?? ''));
            $secondUserId  = (int)($r['secondparent_id'] ?? 0);

            if ($primaryUserId <= 0 || $email === '') { $skipped++; continue; }

            // students for this primary parent
            $students = $this->db->query("SELECT id FROM students WHERE parent_id = ?", [$primaryUserId])->getResultArray();
            if (!$students) { $skipped++; continue; }

            // resolve/create the second parent user
            $userRow = null;
            if ($secondUserId > 0) {
                $userRow = $this->db->table('users')->select('id, firstname, lastname')->where('id', $secondUserId)->get()->getRowArray();
            }
            if (!$userRow) {
                $userRow = $this->db->table('users')->select('id, firstname, lastname')->where('email', $email)->get()->getRowArray();
            }

            if (!$userRow) {
                // STUB USER with safe defaults for your NOT NULL columns
                $this->db->table('users')->insert([
                    'firstname'            => $first ?: '(Parent)',
                    'lastname'             => $last  ?: '(Unspecified)',
                    'email'                => $email,
                    'cellphone'            => '',
                    'address_street'       => '',
                    'apt'                  => null,
                    'city'                 => '',
                    'state'                => '',
                    'zip'                  => '',
                    'accept_school_policy' => 0,
                    'is_verified'          => 0,
                    'status'               => 'Active',
                    'is_suspended'         => 0,
                    'failed_attempts'      => 0,
                    'password'             => password_hash(bin2hex(random_bytes(8)), PASSWORD_BCRYPT),
                    'created_at'           => utc_now(),
                    'updated_at'           => utc_now(),
                    'token'                => null,
                    'account_id'           => null,
                    'user_type'            => 'primary',
                    'semester'             => '',
                    'school_year'          => null,
                    'rfid_tag'             => null,
                    'last_failed_at'       => null,
                ]);
                if ($this->db->affectedRows() === 0) {
                    $err = $this->db->error();
                    echo "[ERROR] users insert failed for {$email}: {$err['code']} {$err['message']}\n";
                    $skipped++; continue;
                }
                $secondUserId = (int)$this->db->insertID();
                $createdUsers++;
                $userRow = ['id' => $secondUserId, 'firstname' => $first, 'lastname' => $last];
            } else {
                $secondUserId = (int)$userRow['id'];
                if (empty($userRow['firstname']) || empty($userRow['lastname'])) {
                    $this->db->table('users')->where('id', $secondUserId)->update([
                        'firstname' => $userRow['firstname'] ?: ($first ?: '(Parent)'),
                        'lastname'  => $userRow['lastname']  ?: ($last  ?: '(Unspecified)'),
                    ]);
                }
            }

            // link second parent to each student’s family
            foreach ($students as $s) {
                $studentId = (int)$s['id'];
                $familyId = $this->familyIdFromStudentPrimary($studentId);
                if (!$familyId) {
                    $familyId = $this->ensureFamilyForPrimaryParent($primaryUserId, $dummy = 0);
                    $this->attachStudentToFamily($studentId, $familyId);
                }
                $linked += $this->attachGuardianUser($familyId, $secondUserId, 'secondary', 0, 1, 0);
            }
        }

        return [$createdUsers, $linked, $skipped, $total];
    }

    // ---------- Helpers ----------

    /** Ensure there is exactly one family per primary parent user. */
    protected function ensureFamilyForPrimaryParent(int $primaryUserId, int &$createdCounter): int
    {
        $code = 'FAM-' . $primaryUserId;
        $row = $this->db->query("SELECT id FROM families WHERE family_code = ?", [$code])->getRowArray();
        if ($row) return (int)$row['id'];

        $this->db->table('families')->insert([
            'family_code'    => $code,
            'household_name' => 'Family of User ' . $primaryUserId,
            'is_active'      => 1,
        ]);
        $createdCounter++;
        return (int)$this->db->insertID();
    }

    /** Idempotent link student → family. */
    protected function attachStudentToFamily(int $studentId, int $familyId): int
    {
        $this->db->query(
            "INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home) VALUES (?, ?, 1)",
            [$familyId, $studentId]
        );
        return $this->db->affectedRows();
    }

    /** Idempotent link guardian user → family. */
    protected function attachGuardianUser(int $familyId, int $userId, string $relation, int $isPrimary, int $receiveEmails, int $receiveSms): int
    {
        $this->db->query(
            "INSERT IGNORE INTO family_guardians (family_id, user_id, relation, is_primary, receive_emails, receive_sms) VALUES (?, ?, ?, ?, ?, ?)",
            [$familyId, $userId, $relation, $isPrimary, $receiveEmails, $receiveSms]
        );
        return $this->db->affectedRows();
    }

    /** Canonical family for a student based on parent_id → FAM-{parent_id}, fallback to any linked family. */
    protected function familyIdFromStudentPrimary(int $studentId): ?int
    {
        $row = $this->db->query("SELECT parent_id FROM students WHERE id = ?", [$studentId])->getRowArray();
        if (!$row || empty($row['parent_id'])) return null;

        $code = 'FAM-' . (int)$row['parent_id'];
        $fam = $this->db->query("SELECT id FROM families WHERE family_code = ?", [$code])->getRowArray();
        if ($fam) return (int)$fam['id'];

        $fam2 = $this->db->query(
            "SELECT family_id FROM family_students WHERE student_id = ? ORDER BY is_primary_home DESC LIMIT 1",
            [$studentId]
        )->getRowArray();
        return $fam2 ? (int)$fam2['family_id'] : null;
    }
}
