<?php

namespace App\Database\Seeds;

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

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

    /** Legacy parents table mapping (fits your schema exactly) */
    protected array $legacy = [
        'table'            => 'parents',
        'firstparent_id'   => 'firstparent_id',          // users.id of primary parent
        'second_user_id'   => 'secondparent_id',         // users.id of 2nd parent (may be 0)
        'second_email'     => 'secondparent_email',
        'second_firstname' => 'secondparent_firstname',
        'second_lastname'  => 'secondparent_lastname',
    ];

    /** Defaults for prefs rows per category (your schema) */
    protected array $prefsDefaults = [
        // category => [via_email, via_sms, cc_all_guardians]
        'attendance' => [1, 0, 1],
        'grade'      => [1, 0, 1],
        'behavior'   => [1, 0, 1],
        'general'    => [1, 0, 1],
    ];

    public function run()
    {
        $this->db = \Config\Database::connect();
        $this->db->transStrict(false);      // don't auto-rollback the entire txn on one failure
        $this->db->transException(false);   // don't throw (so we can print errors ourselves)

        // Start a transaction so the DB stays consistent; we'll print status after.
        $this->db->transStart();

        [$familiesCreated, $studentLinks]  = $this->ensureFamiliesAndLinks();
        $primaryLinked                     = $this->linkPrimaryGuardians();
        [$stubUsers, $secondaryLinked]     = $this->importSecondaryGuardiansFromParents();
        $prefsUpserts                      = $this->seedFamilyCommPrefsPerCategory();

        $this->db->transComplete();

        echo PHP_EOL;
        $status = $this->db->transStatus();
        echo $status ? "[TXN] Transaction COMMITTED.\n" : "[TXN] Transaction FAILED.\n";
        if (! $status) {
            $err = $this->db->error();
            echo "      DB error: " . ($err['message'] ?? 'unknown') . " (code " . ($err['code'] ?? 'n/a') . ")\n";
        }
        echo "Families created:                {$familiesCreated}\n";
        echo "family_students links inserted:  {$studentLinks}\n";
        echo "Primary guardians linked:        {$primaryLinked}\n";
        echo "Stub users created (secondary):  {$stubUsers}\n";
        echo "Secondary guardians linked:      {$secondaryLinked}\n";
        echo "family_comm_prefs upserts:       {$prefsUpserts}\n";
        echo PHP_EOL;
    }


    protected function exec(string $label, string $sql): int
{
    $ok = $this->db->query($sql);
    if (! $ok) {
        $err = $this->db->error();
        echo "[ERROR] {$label}: " . ($err['message'] ?? 'unknown') . " (code " . ($err['code'] ?? 'n/a') . ")\n";
        return 0;
    }
    $n = (int) $this->db->affectedRows();
    echo "[OK] {$label}: affectedRows={$n}\n";
    return $n;
}

    /**
     * Create families from students where parent_id maps to a real users.id,
     * then link all students to their family's id.
     */
protected function ensureFamiliesAndLinks(): array
{
    $familiesCreated = $this->exec(
        'families insert',
        "
        INSERT IGNORE INTO families (family_code, household_name, is_active, created_at, updated_at)
        SELECT DISTINCT
            CONCAT('FAM-', s.parent_id),
            CONCAT('Family of User ', s.parent_id),
            1, NOW(), NOW()
        FROM students s
        JOIN users u ON u.id = s.parent_id
        WHERE s.parent_id IS NOT NULL
        "
    );

    $studentLinks = $this->exec(
        'family_students insert',
        "
        INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home)
        SELECT f.id, s.id, 1
        FROM students s
        JOIN users u ON u.id = s.parent_id
        JOIN families f ON f.family_code = CONCAT('FAM-', s.parent_id)
        "
    );

    // Backfill addresses/phone/household_name from users if empty
    $this->exec(
        'families backfill address/phone/name',
        "
        UPDATE families f
        JOIN users u ON u.id = CAST(SUBSTRING(f.family_code, 5) AS UNSIGNED)
        SET
          f.address_line1 = COALESCE(NULLIF(f.address_line1, ''), NULLIF(u.address_street, '')),
          f.city          = COALESCE(NULLIF(f.city, ''),          NULLIF(u.city, '')),
          f.state         = COALESCE(NULLIF(f.state, ''),         NULLIF(u.state, '')),
          f.postal_code   = COALESCE(NULLIF(f.postal_code, ''),   NULLIF(u.zip, '')),
          f.primary_phone = COALESCE(NULLIF(f.primary_phone, ''), NULLIF(u.cellphone, '')),
          f.household_name= CASE
                               WHEN f.household_name IS NULL OR f.household_name = ''
                               THEN TRIM(CONCAT('Family of ', NULLIF(u.firstname, ''), ' ', NULLIF(u.lastname, '')))
                               ELSE f.household_name
                             END
        "
    );

    return [$familiesCreated, $studentLinks];
}



    /**
     * Link primary guardians using student-anchored joins (no family_code parsing assumptions).
     * relation uses a safe generic 'guardian' (fits varchar(32) and common enums).
     */
protected function linkPrimaryGuardians(): int
{
    // Log candidate count (already printed earlier for you)
    $row = $this->db->query("
        SELECT COUNT(*) AS c FROM (
          SELECT DISTINCT fs.family_id, u.id AS user_id
          FROM family_students fs
          JOIN students s ON s.id = fs.student_id
          JOIN users u    ON u.id = s.parent_id
          WHERE s.parent_id IS NOT NULL
        ) X
    ")->getRowArray();
    echo "[DEBUG] Primary guardian candidates (via students): " . (int)($row['c'] ?? 0) . "\n";

    // Path A: student-anchored (ignore duplicates/violations)
    $linkedA = $this->exec(
        'primary guardians insert A (student-anchored, IGNORE)',
        "
        INSERT IGNORE INTO family_guardians
            (family_id, user_id, relation, is_primary, receive_emails, receive_sms)
        SELECT DISTINCT
            fs.family_id,
            u.id,
            'guardian', 1, 1, 0
        FROM family_students fs
        JOIN students s ON s.id = fs.student_id
        JOIN users u    ON u.id = s.parent_id
        WHERE s.parent_id IS NOT NULL
        "
    );

    // Path B: via family_code (belt & suspenders)
    $linkedB = $this->exec(
        'primary guardians insert B (family_code, IGNORE)',
        "
        INSERT IGNORE INTO family_guardians
            (family_id, user_id, relation, is_primary, receive_emails, receive_sms)
        SELECT f.id, u.id, 'guardian', 1, 1, 0
        FROM families f
        JOIN users u ON u.id = CAST(SUBSTRING(f.family_code, 5) AS UNSIGNED)
        "
    );

    return $linkedA + $linkedB;
}

    /**
     * Create/link secondary guardians from legacy parents:
     *  - Create stub users for secondparent_email not present in users.
     *  - Link those (or explicit secondparent_id) to all families of the first parent’s students.
     */
protected function importSecondaryGuardiansFromParents(): array
{
    $L = $this->legacy;

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

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

    $stubUsers = $this->exec(
        'secondary guardian stubs (users)',
        "
        INSERT INTO users
          (firstname, lastname, email, cellphone, address_street, apt, city, state, zip,
           accept_school_policy, is_verified, status, is_suspended, failed_attempts,
           password, created_at, updated_at, token, account_id, user_type, semester,
           school_year, rfid_tag, last_failed_at)
        SELECT
          NULLIF(p.{$L['second_firstname']},''),
          NULLIF(p.{$L['second_lastname']},''),
          p.{$L['second_email']},
          '', '', NULL, '', '', '',
          0, 0, 'Active', 0, 0,
          '$2y$10abcdefghijklmnopqrstuv',
          NOW(), NOW(), NULL, NULL, 'secondary',
          '', NULL, NULL, NULL
        FROM {$L['table']} p
        LEFT JOIN users u ON u.email = p.{$L['second_email']}
        WHERE p.{$L['second_email']} IS NOT NULL
          AND p.{$L['second_email']} <> ''
          AND u.id IS NULL
        "
    );

    $secondaryLinked = $this->exec(
        'secondary guardians insert (IGNORE)',
        "
        INSERT IGNORE INTO family_guardians
          (family_id, user_id, relation, is_primary, receive_emails, receive_sms)
        SELECT DISTINCT
          fs.family_id,
          COALESCE(u2.id, u_email.id) AS user_id,
          'guardian', 0, 1, 0
        FROM {$L['table']} p
        JOIN students s
          ON s.parent_id = p.{$L['firstparent_id']}
          OR s.parent_id = p.id
        JOIN family_students fs ON fs.student_id = s.id
        LEFT JOIN users u2      ON u2.id = NULLIF(p.{$L['second_user_id']}, 0)
        LEFT JOIN users u_email ON u_email.email = p.{$L['second_email']}
        WHERE p.{$L['second_email']} IS NOT NULL
          AND p.{$L['second_email']} <> ''
          AND COALESCE(u2.id, u_email.id) IS NOT NULL
        "
    );

    return [$stubUsers, $secondaryLinked];
}


    /**
     * Seed one prefs row per (family_id, category) with your defaults.
     * Counts how many rows were *actually inserted* across all categories.
     */
    protected function seedFamilyCommPrefsPerCategory(): int
    {
        if (! $this->db->tableExists('family_comm_prefs')) {
            echo "[INFO] family_comm_prefs not found; skipping prefs seed.\n";
            return 0;
        }

        $insertedTotal = 0;

        foreach ($this->prefsDefaults as $category => [$viaEmail, $viaSms, $ccAll]) {
            // Count how many families are missing this category BEFORE
            $row = $this->db->query("
                SELECT COUNT(*) AS c
                FROM families f
                LEFT JOIN family_comm_prefs p
                  ON p.family_id = f.id AND p.category = ?
                WHERE p.family_id IS NULL
            ", [$category])->getRowArray();
            $missing = (int)($row['c'] ?? 0);

            if ($missing > 0) {
                $this->db->query("
                    INSERT INTO family_comm_prefs (family_id, category, via_email, via_sms, cc_all_guardians)
                    SELECT f.id, ?, ?, ?, ?
                    FROM families f
                    LEFT JOIN family_comm_prefs p
                      ON p.family_id = f.id AND p.category = ?
                    WHERE p.family_id IS NULL
                ", [$category, (int)$viaEmail, (int)$viaSms, (int)$ccAll, $category]);

                $insertedTotal += $missing;
            }
        }

        return $insertedTotal;
    }

    /** Utility: check if a column exists (case-insensitive) */
    protected function columnExists(string $table, string $column): bool
    {
        if (! $this->db->tableExists($table)) return false;
        $cols = array_map('strtolower', array_column($this->db->getFieldData($table), 'name'));
        return in_array(strtolower($column), $cols, true);
    }
}
