<?php

namespace App\Controllers\View;

use App\Controllers\BaseController;
use CodeIgniter\Database\BaseConnection;

// MODELS you should already have (or create tiny ones if not)
use App\Models\FamilyModel;
use App\Models\FamilyGuardianModel;
use App\Models\FamilyStudentModel;

// Your app's models
use App\Models\StudentModel;
use App\Models\UserModel;

/**
 * FamilyController
 *
 * Handles creating/linking Family ←→ Guardians (users) ←→ Students,
 * including bootstrap from existing schema where students.parent_id is the
 * “first parent”, and a second parent may be present as a users row
 * or only as an email (stub user creation).
 */
class FamilyController extends BaseController
{
    protected FamilyModel $families;
    protected FamilyGuardianModel $guardians;
    protected FamilyStudentModel $familyStudents;

    protected StudentModel $students;
    protected UserModel $users;

    protected BaseConnection $db;

    public function __construct()
    {
        $this->families       = new FamilyModel();
        $this->guardians      = new FamilyGuardianModel();
        $this->familyStudents = new FamilyStudentModel();

        $this->students = new StudentModel();
        $this->users    = new UserModel();

        $this->db = \Config\Database::connect();
    }

    /* =========================================================
     * SECTION A — APIs your UI uses
     * =======================================================*/

    // GET /api/students/{id}/families
    public function familiesByStudent(int $studentId)
    {
        $rows = $this->db->query(
            "SELECT f.*, fs.is_primary_home
             FROM family_students fs
             JOIN families f ON f.id = fs.family_id
             WHERE fs.student_id = ? AND f.is_active = 1
             ORDER BY fs.is_primary_home DESC, f.household_name",
            [$studentId]
        )->getResultArray();

        return $this->response->setJSON(['data' => $rows]);
    }

    // GET /api/families/{id}/guardians
    public function guardiansByFamily(int $familyId)
    {
        $rows = $this->db->query(
            "SELECT u.id AS user_id, u.firstname, u.lastname, u.email,
                    fg.relation, fg.is_primary, fg.receive_emails, fg.receive_sms
             FROM family_guardians fg
             JOIN users u ON u.id = fg.user_id
             WHERE fg.family_id = ?
             ORDER BY fg.is_primary DESC, u.lastname, u.firstname",
            [$familyId]
        )->getResultArray();

        return $this->response->setJSON(['data' => $rows]);
    }

    /* =========================================================
     * SECTION B — Bootstrap & Linking helpers
     * =======================================================*/

    // POST /families/bootstrap
    // Creates/ensures families for every student with parent_id,
    // links the student to that family, and (optionally) links a second parent.
    public function bootstrap()
    {
        // Optionally restrict this to admins
        // if (! $this->userCan('families.bootstrap')) return $this->deny();

        // Guard: ensure required tables exist
        foreach (['families','family_students','family_guardians'] as $t) {
            if (! $this->db->tableExists($t)) {
                return $this->response->setStatusCode(500)->setJSON([
                    'status'  => 'error',
                    'message' => "Missing required table '{$t}'. Run migrations: php spark migrate",
                ]);
            }
        }

        $this->db->transStart();

        // 1) Get all distinct primary parents from students.parent_id
        $primaryParents = $this->db->query(
            "SELECT DISTINCT parent_id FROM students WHERE parent_id IS NOT NULL"
        )->getResultArray();

        $created = 0;
        $linkedStudents = 0;
        $linkedGuardians = 0;

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

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

            // Link all students of this primary parent
            $students = $this->db->query(
                "SELECT id FROM students WHERE parent_id = ?",
                [$primaryUserId]
            )->getResultArray();

            foreach ($students as $s) {
                $linkedStudents += $this->attachStudentToFamily((int)$s['id'], $familyId);
            }

            // Ensure primary parent is guardian on that family
            $linkedGuardians += $this->attachGuardianUser($familyId, $primaryUserId, 'primary', true, 1, 0);
        }

        $this->db->transComplete();

        $payload = [
            'status'           => $this->db->transStatus() ? 'ok' : 'error',
            'families_created' => $created,
            'students_linked'  => $linkedStudents,
            'guardians_linked' => $linkedGuardians,
        ];

        // If accessed via GET (browser), redirect back with flash
        if (strtolower($this->request->getMethod()) === 'get') {
            $msg = json_encode($payload);
            return redirect()->to('/family')->with('message', "Bootstrap result: {$msg}");
        }

        return $this->response->setJSON($payload);
    }

    // POST /families/attach-second-by-user
    // body: student_id, user_id, relation='secondary'
    public function attachSecondByUser()
    {
        $studentId = (int) $this->request->getPost('student_id');
        $userId    = (int) $this->request->getPost('user_id');
        $relation  = (string) ($this->request->getPost('relation') ?? 'secondary');

        if (!$studentId || !$userId) return $this->bad('student_id and user_id required');

        $familyId = $this->familyIdFromStudentPrimary($studentId);
        if (!$familyId) return $this->bad('No primary family found for this student');

        $rows = $this->attachGuardianUser($familyId, $userId, $relation, false, 1, 0);

        return $this->response->setJSON(['status' => 'ok', 'attached' => $rows, 'family_id' => $familyId]);
    }

    // POST /families/attach-second-by-email
    // body: student_id, email, firstname, lastname, relation='secondary'
    // Creates a stub user if email not in users, then links.
    public function attachSecondByEmail()
    {
        $studentId = (int) $this->request->getPost('student_id');
        $email     = trim((string)$this->request->getPost('email'));
        $first     = trim((string)$this->request->getPost('firstname'));
        $last      = trim((string)$this->request->getPost('lastname'));
        $relation  = (string) ($this->request->getPost('relation') ?? 'secondary');

        if (!$studentId || !$email) return $this->bad('student_id and email required');

        $familyId = $this->familyIdFromStudentPrimary($studentId);
        if (!$familyId) return $this->bad('No primary family found for this student');

        $user = $this->users->where('email', $email)->first();
        if (!$user) {
            // Create a minimal/stub user; adjust fields to your schema
            $this->users->insert([
                'firstname' => $first ?: '',
                'lastname'  => $last  ?: '',
                'email'     => $email,
                'status'    => 'Active',
                'user_type' => 'secondary', // align with secondary guardian role
            ]);
            $userId = (int) $this->users->getInsertID();
        } else {
            $userId = (int) $user['id'];
        }

        $rows = $this->attachGuardianUser($familyId, $userId, $relation, false, 1, 0);

        return $this->response->setJSON(['status' => 'ok', 'attached' => $rows, 'family_id' => $familyId, 'user_id' => $userId]);
    }

    /* =========================================================
     * SECTION C — Maintenance actions
     * =======================================================*/

    // POST /families/set-primary-home
    // body: family_id, student_id, is_primary_home (0/1)
    public function setPrimaryHome()
    {
        $familyId = (int) $this->request->getPost('family_id');
        $studentId = (int) $this->request->getPost('student_id');
        $flag     = (int) $this->request->getPost('is_primary_home');

        if (!$familyId || !$studentId) return $this->bad('family_id and student_id required');

        $this->familyStudents
            ->where(['family_id' => $familyId, 'student_id' => $studentId])
            ->set(['is_primary_home' => $flag ? 1 : 0])
            ->update();

        return $this->response->setJSON(['status' => 'ok']);
    }

    // POST /families/set-guardian-flags
    // body: family_id, user_id, receive_emails(0/1), is_primary(0/1), receive_sms(0/1)
    public function setGuardianFlags()
    {
        $familyId = (int) $this->request->getPost('family_id');
        $userId   = (int) $this->request->getPost('user_id');

        if (!$familyId || !$userId) return $this->bad('family_id and user_id required');

        $data = [];
        foreach (['receive_emails', 'is_primary', 'receive_sms', 'relation'] as $k) {
            if (null !== $this->request->getPost($k)) {
                $val = $this->request->getPost($k);
                $data[$k] = in_array($k, ['receive_emails', 'is_primary', 'receive_sms'])
                    ? (int)$val
                    : (string)$val;
            }
        }
        if (!$data) return $this->bad('No flags provided');

        $this->guardians->where(['family_id' => $familyId, 'user_id' => $userId])->set($data)->update();

        return $this->response->setJSON(['status' => 'ok']);
    }

    // POST /families/unlink-guardian
    // body: family_id, user_id
    public function unlinkGuardian()
    {
        $familyId = (int) $this->request->getPost('family_id');
        $userId   = (int) $this->request->getPost('user_id');
        if (!$familyId || !$userId) return $this->bad('family_id and user_id required');

        $this->guardians->where(['family_id' => $familyId, 'user_id' => $userId])->delete();
        return $this->response->setJSON(['status' => 'ok']);
    }

    // POST /families/unlink-student
    // body: family_id, student_id
    public function unlinkStudent()
    {
        $familyId  = (int) $this->request->getPost('family_id');
        $studentId = (int) $this->request->getPost('student_id');
        if (!$familyId || !$studentId) return $this->bad('family_id and student_id required');

        $this->familyStudents->where(['family_id' => $familyId, 'student_id' => $studentId])->delete();
        return $this->response->setJSON(['status' => 'ok']);
    }

    /* =========================================================
     * SECTION D — Private helpers
     * =======================================================*/

    // Ensure there is exactly one family per primary parent (users.id)
    // Returns $familyId and increments $created by reference if newly created.
    protected function ensureFamilyForPrimaryParent(int $primaryUserId, int &$createdCounter): int
    {
        $code = 'FAM-' . $primaryUserId;
        $row = $this->families->where('family_code', $code)->first();
        if ($row) return (int)$row['id'];

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

    // Attach a student to a family (idempotent; returns rows affected >0 if inserted)
    protected function attachStudentToFamily(int $studentId, int $familyId): int
    {
        // INSERT IGNORE pattern
        $sql = "INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home)
                VALUES (?, ?, 1)";
        $this->db->query($sql, [$familyId, $studentId]);
        return $this->db->affectedRows();
    }

    // Attach a guardian user to family (idempotent)
    protected function attachGuardianUser(
        int $familyId,
        int $userId,
        string $relation = 'primary',
        bool $isPrimary = false,
        int $receiveEmails = 1,
        int $receiveSms = 0
    ): int {
        $sql = "INSERT IGNORE INTO family_guardians (family_id, user_id, relation, is_primary, receive_emails, receive_sms)
                VALUES (?, ?, ?, ?, ?, ?)";
        $this->db->query($sql, [$familyId, $userId, $relation, $isPrimary ? 1 : 0, $receiveEmails, $receiveSms]);
        return $this->db->affectedRows();
    }

    // Find the “primary” family for a student = family created from parent_id
    protected function familyIdFromStudentPrimary(int $studentId): ?int
    {
        // 1) Get primary parent id for the student
        $st = $this->students->select('parent_id')->find($studentId);
        if (!$st || empty($st['parent_id'])) return null;

        // 2) The canonical family uses code FAM-{parent_id}
        $code = 'FAM-' . (int)$st['parent_id'];
        $row = $this->families->select('id')->where('family_code', $code)->first();
        if ($row) return (int)$row['id'];

        // If not found, fall back to any family linked already
        $row = $this->db->query(
            "SELECT family_id FROM family_students WHERE student_id = ? ORDER BY is_primary_home DESC LIMIT 1",
            [$studentId]
        )->getRowArray();

        return $row ? (int)$row['family_id'] : null;
    }

    // Simple 400
    protected function bad(string $msg)
    {
        return $this->response->setStatusCode(400)->setJSON(['status' => 'error', 'message' => $msg]);
    }

    // Example permission check hook (plug your own logic)
    protected function userCan(string $perm): bool
    {
        $perms = (array) (session('permissions') ?? []);
        return in_array($perm, $perms, true);
    }

    protected function deny()
    {
        return redirect()->to('/access_denied')->setStatusCode(403);
    }

    // Legacy import helper: map secondary parents from legacy 'parents' table
    public function importSecondParentsFromLegacy()
    {
        // Protect this route (e.g., admin only) via filter in routes
        $L = [
            'table'            => 'parents',
            'firstparent_id'   => 'firstparent_id',          // users.id of primary (first) parent
            'second_user_id'   => 'secondparent_id',         // users.id of second parent (optional)
            'second_email'     => 'secondparent_email',
            'second_firstname' => 'secondparent_firstname',
            'second_lastname'  => 'secondparent_lastname',
        ];

        if (!$this->db->tableExists($L['table'])) {
            return $this->response->setJSON(['status' => 'error', 'message' => "Legacy table '{$L['table']}' not found"]);
        }
        foreach (['families','family_students','family_guardians'] as $t) {
            if (! $this->db->tableExists($t)) {
                return $this->response->setStatusCode(500)->setJSON([
                    'status'  => 'error',
                    'message' => "Missing required table '{$t}'. Run migrations: php spark migrate",
                ]);
            }
        }

        $rows = $this->db->table($L['table'])
            ->select(
                "{$L['firstparent_id']} AS first_id, " .
                "{$L['second_user_id']} AS second_id, " .
                "{$L['second_email']} AS email, " .
                "{$L['second_firstname']} AS firstname, " .
                "{$L['second_lastname']} AS lastname",
                false
            )
            ->groupStart()
                ->where("{$L['second_user_id']} !=", 0)
                ->orWhere("{$L['second_email']} !=", '')
            ->groupEnd()
            ->get()->getResultArray();

        $createdUsers = 0;
        $linked = 0;
        $skipped = 0;

        foreach ($rows as $r) {
            $firstId = (int)($r['first_id'] ?? 0);
            $secondId = (int)($r['second_id'] ?? 0);
            $email    = trim((string)($r['email'] ?? ''));

            if (!$firstId || (!$secondId && $email === '')) {
                $skipped++;
                continue;
            }

            // Ensure/find family by primary parent
            $code = 'FAM-' . $firstId;
            $fam  = $this->families->select('id')->where('family_code', $code)->first();
            if ($fam) {
                $familyId = (int)$fam['id'];
            } else {
                $tmp = 0; // counter sink
                $familyId = $this->ensureFamilyForPrimaryParent($firstId, $tmp);
            }

            // Resolve/create user
            $userId = 0;
            if ($secondId > 0) {
                $userId = $secondId;
            } else {
                $user = $this->users->where('email', $email)->first();
                if (!$user) {
                    $this->users->insert([
                        'firstname' => $r['firstname'] ?? '',
                        'lastname'  => $r['lastname']  ?? '',
                        'email'     => $email,
                        'status'    => 'Active',
                        'user_type' => 'secondary',
                    ]);
                    $userId = (int)$this->users->getInsertID();
                    $createdUsers++;
                } else {
                    $userId = (int)$user['id'];
                }
            }

            // Ensure all students for this primary parent are linked to this family
            $stuRows = $this->db->query("SELECT id FROM students WHERE parent_id = ?", [$firstId])->getResultArray();
            foreach ($stuRows as $sr) {
                $sid = (int)($sr['id'] ?? 0);
                if ($sid > 0) {
                    $this->attachStudentToFamily($sid, $familyId);
                }
            }

            // Link as guardian (idempotent)
            $linked += $this->attachGuardianUser($familyId, $userId, 'guardian', false, 1, 0);
        }

        $payload = [
            'status'           => 'ok',
            'created_users'    => $createdUsers,
            'guardians_linked' => $linked,
            'skipped'          => $skipped,
            'total_source'     => count($rows),
        ];

        if (strtolower($this->request->getMethod()) === 'get') {
            $msg = json_encode($payload);
            return redirect()->to('/family')->with('message', "Import legacy result: {$msg}");
        }

        return $this->response->setJSON($payload);
    }
}
