<?php

namespace App\Controllers\View;

use App\Controllers\BaseController;
use CodeIgniter\HTTP\ResponseInterface;
use App\Models\InvoiceModel;
use App\Models\PaymentModel;
use App\Models\StudentClassModel;
use App\Models\ConfigurationModel;

class FamilyAdminController extends BaseController
{
    public function index(): ResponseInterface
    {
        $db = \Config\Database::connect();
        $studentId = (int) ($this->request->getGet('student_id') ?? 0);
        $guardianId = (int) ($this->request->getGet('guardian_id') ?? 0);
        $data = ['student' => null, 'families' => [], 'guardians' => [], 'students' => []];

        // Simple student list for select
        $data['students'] = $db->query("SELECT id, CONCAT(lastname, ', ', firstname) AS name FROM students ORDER BY lastname, firstname")->getResultArray();
        // Preload search datasets (students + guardians/parents)
        $data['searchStudents'] = $db->query("SELECT id, firstname, lastname FROM students ORDER BY lastname, firstname")->getResultArray();
        $data['searchGuardians'] = $db->query(
            "SELECT DISTINCT u.id, u.firstname, u.lastname, u.email, u.cellphone
               FROM family_guardians fg
               JOIN users u ON u.id = fg.user_id
              ORDER BY u.lastname, u.firstname"
        )->getResultArray();

        // If a guardian is provided, resolve one of their students and redirect to use existing flow
        if (!$studentId && $guardianId) {
            $row = $db->query(
                "SELECT s.id AS student_id
                   FROM family_guardians fg
                   JOIN family_students fs ON fs.family_id = fg.family_id
                   JOIN students s ON s.id = fs.student_id
                  WHERE fg.user_id = ?
                  ORDER BY s.lastname, s.firstname
                  LIMIT 1",
                [$guardianId]
            )->getRowArray();
            if (!$row) {
                $row = $db->query(
                    "SELECT s.id AS student_id
                       FROM students s
                      WHERE s.parent_id = ?
                      ORDER BY s.lastname, s.firstname
                      LIMIT 1",
                    [$guardianId]
                )->getRowArray();
            }
            if ($row && !empty($row['student_id'])) {
                return redirect()->to(site_url('family?student_id='.(int)$row['student_id']));
            }
        }

        if ($studentId) {
            $data['student'] = $db->query("SELECT id, firstname, lastname FROM students WHERE id = ?", [$studentId])->getRowArray();

            // Fetch all families for this student with extended fields
            $families = $db->query(
                "SELECT f.id, f.family_code, f.household_name, f.address_line1, f.address_line2, f.city, f.state, f.postal_code, f.country,
                        f.primary_phone, f.preferred_lang, f.preferred_contact_method, f.is_active,
                        fs.is_primary_home
                 FROM family_students fs
                 JOIN families f ON f.id = fs.family_id
                 WHERE fs.student_id = ?
                 ORDER BY fs.is_primary_home DESC, f.household_name",
                [$studentId]
            )->getResultArray();

            // Enrich each family with guardians, students, and financials
            $invoiceModel = new InvoiceModel();
            $paymentModel = new PaymentModel();
            $studentClassModel = new StudentClassModel();
            $configModel = new ConfigurationModel();
            $schoolYear = (string) ($configModel->getConfig('school_year') ?? '');

            foreach ($families as &$fam) {
                $fid = (int) $fam['id'];

                // Guardians (with contact info)
                $guardians = $db->query(
                    "SELECT u.id AS user_id, u.firstname, u.lastname, u.email, u.cellphone,
                            u.address_street, u.city, u.state, u.zip,
                            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",
                    [$fid]
                )->getResultArray();
                $fam['guardians'] = $guardians;

                // Students in this family
                $studentsRows = $db->query(
                    "SELECT s.id, s.firstname, s.lastname
                     FROM family_students fs
                     JOIN students s ON s.id = fs.student_id
                     WHERE fs.family_id = ?
                     ORDER BY s.lastname, s.firstname",
                    [$fid]
                )->getResultArray();
                // Enrich with grade label if available
                if (!empty($studentsRows)) {
                    foreach ($studentsRows as &$sr) {
                        $sid = (int) ($sr['id'] ?? 0);
                        $sr['grade'] = $sid ? (string) ($studentClassModel->getClassSectionsByStudentId($sid, $schoolYear) ?? '') : '';
                    }
                    unset($sr);
                }
                $fam['students'] = $studentsRows;

                // Financials: invoices and payments for all guardians (by user_id)
                $parentIds = array_map(static fn($g) => (int)($g['user_id'] ?? 0), $guardians);
                $parentIds = array_values(array_filter($parentIds));

                $fam['invoices'] = [];
                $fam['payments'] = [];
                $fam['finance_summary'] = [
                    'invoices_count' => 0,
                    'total_amount'   => 0.0,
                    'paid_amount'    => 0.0,
                    'balance'        => 0.0,
                ];

                if (!empty($parentIds)) {
                    // Invoices
                    $invRows = $db->table('invoices')
                        ->select('id, parent_id, invoice_number, status, total_amount, paid_amount, balance, issue_date, due_date')
                        ->whereIn('parent_id', $parentIds)
                        ->orderBy('issue_date', 'DESC')
                        ->get()->getResultArray();
                    $fam['invoices'] = $invRows;
                    // Map invoice id -> number for payments table
                    $invoiceMap = [];
                    foreach ($invRows as $ir) {
                        $invoiceMap[(int)$ir['id']] = (string)($ir['invoice_number'] ?? '');
                    }
                    $fam['invoice_map'] = $invoiceMap;

                    // Aggregate summary
                    foreach ($invRows as $ir) {
                        $fam['finance_summary']['invoices_count']++;
                        $fam['finance_summary']['total_amount'] += (float)($ir['total_amount'] ?? 0);
                        $fam['finance_summary']['paid_amount']  += (float)($ir['paid_amount']  ?? 0);
                        $fam['finance_summary']['balance']      += (float)($ir['balance']      ?? 0);
                    }

                    // Recent payments (limit 10)
                    $payRows = $db->table('payments p')
                        ->select('p.id, p.parent_id, p.invoice_id, p.paid_amount, p.payment_method, p.payment_date, p.status AS payment_status, p.installment_seq, p.number_of_installments, i.invoice_number, i.balance AS invoice_current_balance, i.status AS invoice_status, i.school_year')
                        ->join('invoices i', 'i.id = p.invoice_id', 'inner')
                        ->whereIn('p.parent_id', $parentIds)
                        ->orderBy('p.payment_date', 'DESC')
                        ->orderBy('p.id', 'DESC')
                        ->limit(10)
                        ->get()->getResultArray();
                    $fam['payments'] = $payRows;
                }
            }
            unset($fam);

            $data['families'] = $families;

            // Back-compat: also expose guardians of first family for old UI pieces
            if (!empty($families)) {
                $familyId = (int)$families[0]['id'];
                $data['guardians'] = $db->query(
                    "SELECT u.id, u.firstname, u.lastname, u.email, fg.relation, fg.is_primary, fg.receive_emails
                     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 service('response')->setBody(view('family/index', $data));
    }

    // GET /family/search?q=..
    public function search(): ResponseInterface
    {
        $db = \Config\Database::connect();
        $q = trim((string)($this->request->getGet('q') ?? ''));
        if ($q === '') {
            return $this->response->setJSON(['items' => []]);
        }
        $qs = '%' . $db->escapeLikeString($q) . '%';

        // Students suggestions
        $students = $db->query(
            "SELECT id, firstname, lastname
               FROM students
              WHERE CONCAT_WS(' ', firstname, lastname) LIKE ?
              ORDER BY lastname, firstname
              LIMIT 8",
            [$qs]
        )->getResultArray();

        // Parents/Guardians suggestions (users)
        $guardians = $db->query(
            "SELECT id, firstname, lastname, email, cellphone
               FROM users
              WHERE (
                     CONCAT_WS(' ', firstname, lastname) LIKE ?
                  OR email LIKE ?
                  OR cellphone LIKE ?
              )
              ORDER BY lastname, firstname
              LIMIT 8",
            [$qs, $qs, $qs]
        )->getResultArray();

        $items = [];
        foreach ($students as $s) {
            $items[] = [
                'type' => 'student',
                'id'   => (int)$s['id'],
                'label'=> trim(($s['firstname'] ?? '').' '.($s['lastname'] ?? '')),
                'sub'  => 'Student',
            ];
        }
        foreach ($guardians as $g) {
            $items[] = [
                'type'  => 'guardian',
                'id'    => (int)$g['id'],
                'label' => trim(($g['firstname'] ?? '').' '.($g['lastname'] ?? '')),
                'sub'   => trim(($g['email'] ?? '').' '.($g['cellphone'] ?? '')),
            ];
        }

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

    // GET /family/card?student_id=.. | guardian_id=.. | family_id=..
    public function card(): ResponseInterface
    {
        $db = \Config\Database::connect();
        $studentId  = (int) ($this->request->getGet('student_id') ?? 0);
        $guardianId = (int) ($this->request->getGet('guardian_id') ?? 0);
        $familyId   = (int) ($this->request->getGet('family_id') ?? 0);

        if (!$familyId) {
            if ($studentId) {
                $row = $db->query(
                    "SELECT f.id
                       FROM family_students fs
                       JOIN families f ON f.id = fs.family_id
                      WHERE fs.student_id = ?
                      ORDER BY fs.is_primary_home DESC, f.household_name
                      LIMIT 1",
                    [$studentId]
                )->getRowArray();
                if (!empty($row['id'])) $familyId = (int) $row['id'];
            } elseif ($guardianId) {
                // 1) Try via guardians link
                $row = $db->query(
                    "SELECT f.id
                       FROM family_guardians fg
                       JOIN families f ON f.id = fg.family_id
                      WHERE fg.user_id = ?
                      ORDER BY f.household_name
                      LIMIT 1",
                    [$guardianId]
                )->getRowArray();
                if (!empty($row['id'])) {
                    $familyId = (int) $row['id'];
                } else {
                    // 2) Fallback via students.parent_id → family_students
                    $row = $db->query(
                        "SELECT f.id
                           FROM students s
                           JOIN family_students fs ON fs.student_id = s.id
                           JOIN families f ON f.id = fs.family_id
                          WHERE s.parent_id = ?
                          ORDER BY fs.is_primary_home DESC, f.household_name
                          LIMIT 1",
                        [$guardianId]
                    )->getRowArray();
                    if (!empty($row['id'])) $familyId = (int) $row['id'];
                }
            }
        }

        if (!$familyId) {
            return $this->response->setStatusCode(404)->setBody('<div class="p-3 text-danger">Family not found.</div>');
        }

        $family = $db->query(
            "SELECT f.id, f.family_code, f.household_name, f.address_line1, f.address_line2, f.city, f.state, f.postal_code, f.country,
                    f.primary_phone, f.preferred_lang, f.preferred_contact_method, f.is_active
               FROM families f
              WHERE f.id = ?",
            [$familyId]
        )->getRowArray();

        if (!$family) {
            return $this->response->setStatusCode(404)->setBody('<div class="p-3 text-danger">Family not found.</div>');
        }

        // Hydrate with guardians, students (+grades), invoices, payments
        $invoiceModel = new \App\Models\InvoiceModel();
        $paymentModel = new \App\Models\PaymentModel();
        $studentClassModel = new \App\Models\StudentClassModel();
        $configModel = new \App\Models\ConfigurationModel();
        $schoolYear = (string) ($configModel->getConfig('school_year') ?? '');

        // Guardians
        $guardians = $db->query(
            "SELECT u.id AS user_id, u.firstname, u.lastname, u.email, u.cellphone,
                    u.address_street, u.city, u.state, u.zip,
                    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();
        $family['guardians'] = $guardians;

        // Students
        $studentsRows = $db->query(
            "SELECT s.id, s.firstname, s.lastname
               FROM family_students fs
               JOIN students s ON s.id = fs.student_id
              WHERE fs.family_id = ?
              ORDER BY s.lastname, s.firstname",
            [$familyId]
        )->getResultArray();
        if (!empty($studentsRows)) {
            foreach ($studentsRows as &$sr) {
                $sid = (int) ($sr['id'] ?? 0);
                $sr['grade'] = $sid ? (string) ($studentClassModel->getClassSectionsByStudentId($sid, $schoolYear) ?? '') : '';
            }
            unset($sr);
        }
        $family['students'] = $studentsRows;

        // Financials
        $parentIds = array_map(static fn($g) => (int)($g['user_id'] ?? 0), $guardians);
        $parentIds = array_values(array_filter($parentIds));

        $family['invoices'] = [];
        $family['payments'] = [];
        $family['finance_summary'] = [
            'invoices_count' => 0,
            'total_amount'   => 0.0,
            'paid_amount'    => 0.0,
            'balance'        => 0.0,
        ];
        // Emergency contacts (by guardian/parent)
        $family['emergency_contacts'] = [];
        if (!empty($parentIds)) {
            // Map guardian name by user_id
            $gmap = [];
            foreach ($guardians as $g) {
                $gid = (int)($g['user_id'] ?? 0);
                if ($gid > 0) $gmap[$gid] = trim(($g['firstname'] ?? '') . ' ' . ($g['lastname'] ?? ''));
            }
            $ecRows = $db->table('emergency_contacts')
                ->select('id, parent_id, emergency_contact_name, relation, cellphone, email, created_at, updated_at')
                ->whereIn('parent_id', $parentIds)
                ->orderBy('updated_at', 'DESC')
                ->get()->getResultArray();
            if (!empty($ecRows)) {
                foreach ($ecRows as &$ec) {
                    $pid = (int)($ec['parent_id'] ?? 0);
                    $ec['parent_label'] = $gmap[$pid] ?? ('Parent #'.$pid);
                }
                unset($ec);
                $family['emergency_contacts'] = $ecRows;
            }
        }

        if (!empty($parentIds)) {
            // Invoices
            $invRows = $db->table('invoices')
                ->select('id, parent_id, invoice_number, status, total_amount, paid_amount, balance, issue_date, due_date')
                ->whereIn('parent_id', $parentIds)
                ->orderBy('issue_date', 'DESC')
                ->get()->getResultArray();
            $family['invoices'] = $invRows;
            $invoiceMap = [];
            foreach ($invRows as $ir) {
                $invoiceMap[(int)$ir['id']] = (string)($ir['invoice_number'] ?? '');
            }
            $family['invoice_map'] = $invoiceMap;

            foreach ($invRows as $ir) {
                $family['finance_summary']['invoices_count']++;
                $family['finance_summary']['total_amount'] += (float)($ir['total_amount'] ?? 0);
                $family['finance_summary']['paid_amount']  += (float)($ir['paid_amount']  ?? 0);
                $family['finance_summary']['balance']      += (float)($ir['balance']      ?? 0);
            }

            // Payments
            $payRows = $db->table('payments p')
                ->select('p.id, p.parent_id, p.invoice_id, p.paid_amount, p.payment_method, p.payment_date, p.status AS payment_status, p.installment_seq, p.number_of_installments, i.invoice_number, i.balance AS invoice_current_balance, i.status AS invoice_status, i.school_year')
                ->join('invoices i', 'i.id = p.invoice_id', 'inner')
                ->whereIn('p.parent_id', $parentIds)
                ->orderBy('p.payment_date', 'DESC')
                ->orderBy('p.id', 'DESC')
                ->limit(10)
                ->get()->getResultArray();
            $family['payments'] = $payRows;
        }

        return service('response')->setBody(view('family/card', ['f' => $family]));
    }

    public function composeEmail()
    {
        $to = trim((string)$this->request->getGet('to'));
        $name = trim((string)$this->request->getGet('name'));
        $returnUrl = trim((string)$this->request->getGet('return_url'));
        if ($returnUrl === '') {
            $returnUrl = trim((string)$this->request->getServer('HTTP_REFERER'));
        }
        if ($returnUrl === '') {
            $returnUrl = site_url('family');
        }

        return view('family/compose_email', [
            'to' => $to,
            'name' => $name,
            'return_url' => $returnUrl,
        ]);
    }

    public function sendComposeEmail()
    {
        if (!$this->request->is('post')) {
            return redirect()->to(site_url('family'));
        }

        $to = trim((string)$this->request->getPost('to'));
        $subject = trim((string)$this->request->getPost('subject'));
        $html = (string)($this->request->getPost('html') ?? '');
        $returnUrl = trim((string)$this->request->getPost('return_url'));

        if ($returnUrl === '' || !$this->isLocalReturnUrl($returnUrl)) {
            $returnUrl = site_url('family');
        }

        if ($to === '' || !filter_var($to, FILTER_VALIDATE_EMAIL)) {
            return redirect()->back()->withInput()->with('error', 'Please enter a valid email address.');
        }
        if ($subject === '') {
            return redirect()->back()->withInput()->with('error', 'Subject is required.');
        }
        if (trim($html) === '') {
            return redirect()->back()->withInput()->with('error', 'Email body is required.');
        }

        $wrapped = view('emails/custom_html', [
            'subject' => $subject,
            'body_html' => $html,
        ]);

        $mailer = new \App\Controllers\View\EmailController();
        $ok = $mailer->sendEmail($to, $subject, $wrapped, 'communication');

        if ($ok) {
            return redirect()->to($returnUrl)->with('status', 'Email sent.');
        }

        return redirect()->to($returnUrl)->with('error', 'Unable to send email.');
    }

    private function isLocalReturnUrl(string $url): bool
    {
        $url = trim($url);
        if ($url === '') return false;

        $parts = parse_url($url);
        if ($parts === false) return false;

        if (!empty($parts['scheme']) || !empty($parts['host'])) {
            $base = parse_url(site_url('/'));
            if (!$base || empty($base['host'])) return false;
            $hostMatch = strcasecmp((string)($parts['host'] ?? ''), (string)$base['host']) === 0;
            return $hostMatch;
        }

        // Relative URL (e.g., /family?x=1 or family?x=1)
        return true;
    }
}
