<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\TabunganModel;
use App\Models\AcademicPeriodModel;
use App\Models\ClassroomModel;
use App\Models\GradeModel;
use App\Models\StudentModel;
use App\Models\SchoolSettingModel;
use App\Models\TeacherModel;

class Tabungan extends BaseController
{
    protected $tabunganModel;
    protected $periodModel;
    protected $classroomModel;
    protected $gradeModel;
    protected $studentModel;
    protected $schoolSettingModel;

    public function __construct()
    {
        $this->tabunganModel       = new TabunganModel();
        $this->periodModel         = new AcademicPeriodModel();
        $this->classroomModel      = new ClassroomModel();
        $this->gradeModel          = new GradeModel();
        $this->studentModel        = new StudentModel();
        $this->schoolSettingModel  = new SchoolSettingModel();
    }

    private function checkLogin()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }
        return null;
    }

    public function index()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return redirect()->to('/dashboard')->with('error', 'Belum ada periode aktif!');
        }

        $data = [
            'title'        => 'Tabungan Siswa',
            'activePeriod' => $activePeriod,
            'grades'       => $this->gradeModel->orderBy('order', 'ASC')->findAll(),
            'classrooms'   => $this->classroomModel->getAllWithRelations(),
        ];

        return view('tabungan/index', $data);
    }

    public function history($studentId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif']);
        }

        $student = $this->studentModel->find($studentId);
        if (!$student) {
            return $this->response->setJSON(['success' => false, 'message' => 'Siswa tidak ditemukan']);
        }

        $balance  = $this->tabunganModel->getBalance($studentId, $activePeriod['id']);
        $history  = $this->tabunganModel->getHistory($studentId, $activePeriod['id']);

        return $this->response->setJSON([
            'success' => true,
            'student' => [
                'id'        => $student['id'],
                'full_name' => $student['full_name'],
                'nis'       => $student['nis'],
            ],
            'balance' => $balance,
            'history' => $history,
        ]);
    }

    public function store()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif']);
        }

        $studentId      = $this->request->getPost('student_id');
        $type           = $this->request->getPost('transaction_type');
        $amount         = (float) $this->request->getPost('amount');
        $transactionDate = $this->request->getPost('transaction_date') ?: date('Y-m-d');
        $notes          = $this->request->getPost('notes');

        if (!$studentId || !$type || !$amount) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Data tidak lengkap!',
            ]);
        }

        if ($amount <= 0) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Nominal harus lebih dari 0!',
            ]);
        }

        if (!in_array($type, ['setoran', 'penarikan'])) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Tipe transaksi tidak valid!',
            ]);
        }

        $student = $this->studentModel->find($studentId);
        if (!$student || $student['status'] !== 'Aktif') {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Siswa tidak ditemukan atau tidak aktif!',
            ]);
        }

        $currentBalance = $this->tabunganModel->getBalance($studentId, $activePeriod['id']);

        if ($type === 'penarikan' && $amount > $currentBalance) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Saldo tidak mencukupi! Saldo saat ini: Rp ' . number_format($currentBalance, 0, ',', '.'),
            ]);
        }

        $balanceAfter = $type === 'setoran'
            ? $currentBalance + $amount
            : $currentBalance - $amount;

        $transactionNumber = $this->tabunganModel->generateTransactionNumber($transactionDate);

        $userId = (int) session()->get('user_id');
        if (!$userId) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Session tidak valid. Silakan login ulang.',
            ]);
        }

        $this->tabunganModel->insert([
            'transaction_number' => $transactionNumber,
            'student_id'         => $studentId,
            'transaction_type'   => $type,
            'amount'             => $amount,
            'balance_after'      => $balanceAfter,
            'transaction_date'   => $transactionDate,
            'notes'              => $notes,
            'recorded_by'        => $userId,
            'academic_period_id' => $activePeriod['id'],
        ]);

        $insertId = $this->tabunganModel->getInsertID();

        return $this->response->setJSON([
            'success'      => true,
            'message'      => 'Transaksi berhasil disimpan!',
            'transaction'  => [
                'id'              => $insertId,
                'transaction_number' => $transactionNumber,
                'type'            => $type,
                'amount'          => $amount,
                'balance_after'   => $balanceAfter,
                'date'            => $transactionDate,
                'notes'           => $notes,
            ],
            'balance'      => $balanceAfter,
        ]);
    }

    public function delete($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $transaction = $this->tabunganModel->find($id);
        if (!$transaction) {
            return $this->response->setJSON(['success' => false, 'message' => 'Transaksi tidak ditemukan']);
        }

        $this->tabunganModel->delete($id);

        $activePeriod = $this->periodModel->getActive();
        $balance = $this->tabunganModel->getBalance($transaction['student_id'], $activePeriod['id']);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Transaksi berhasil dihapus',
            'balance' => $balance,
        ]);
    }

    public function report()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return redirect()->to('/dashboard')->with('error', 'Belum ada periode aktif!');
        }

        $classroomId = $this->request->getGet('classroom_id');

        $waService = new \App\Services\WhatsappService();
        $waConfigured = $waService->isConfigured();

        $data = [
            'title'        => 'Laporan Tabungan',
            'activePeriod' => $activePeriod,
            'grades'       => $this->gradeModel->orderBy('order', 'ASC')->findAll(),
            'classrooms'   => $this->classroomModel->getAllWithRelations(),
            'report'       => $this->tabunganModel->getReportByClass($activePeriod['id'], $classroomId),
            'selectedClassroom' => $classroomId,
            'waConfigured' => $waConfigured,
            'waTabunganEnabled' => $waService->isFeatureEnabled('tabungan'),
            'periods'      => $this->periodModel->getAllWithYear(),
        ];

        return view('tabungan/report', $data);
    }

    public function printSlip($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $transaction = $this->tabunganModel->select('tabungan_transactions.*, users.name as recorded_by_name, students.full_name, students.nis')
            ->join('users', 'users.id = tabungan_transactions.recorded_by', 'left')
            ->join('students', 'students.id = tabungan_transactions.student_id', 'left')
            ->find($id);

        if (!$transaction) {
            return redirect()->to('/tabungan')->with('error', 'Transaksi tidak ditemukan');
        }

        $data = [
            'title'       => 'Slip Transaksi Tabungan',
            'transaction' => $transaction,
            'tabunganOfficerName' => $this->getTabunganOfficerName(),
        ];

        return view('tabungan/print_slip', $data);
    }

    public function printReport()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return redirect()->to('/dashboard')->with('error', 'Belum ada periode aktif!');
        }

        $classroomId = $this->request->getGet('classroom_id');

        $data = [
            'title'        => 'Laporan Tabungan Siswa',
            'activePeriod' => $activePeriod,
            'report'       => $this->tabunganModel->getReportByClass($activePeriod['id'], $classroomId),
            'classroom'    => $classroomId ? $this->classroomModel->select('classrooms.name, grades.name as grade_name')
                 ->join('grades', 'grades.id = classrooms.grade_id')
                 ->find($classroomId) : null,
            'schoolSettings' => $this->schoolSettingModel->first(),
            'letterSettings' => $this->getLetterSettings(),
            'tabunganOfficerName' => $this->getTabunganOfficerName(),
        ];

        $html = view('tabungan/print_report', $data);

        $tempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
        if (!is_dir($tempDir)) {
            @mkdir($tempDir, 0777, true);
        }

        $mpdf = new \Mpdf\Mpdf([
            'tempDir'       => $tempDir,
            'orientation'   => 'P',
            'format'        => 'A4',
            'margin_top'    => 12,
            'margin_bottom' => 12,
            'margin_left'   => 10,
            'margin_right'  => 10,
            'default_font'  => 'dejavusans',
            'default_font_size' => 8,
        ]);
        $mpdf->SetTitle('Laporan Tabungan Siswa');
        $mpdf->WriteHTML($html);

        $filename = 'laporan-tabungan-' . ($classroom['name'] ?? 'semua-kelas') . '-' . date('Ymd') . '.pdf';
        $filename = preg_replace('/[^A-Za-z0-9._-]+/', '-', $filename);

        $pdf = $mpdf->Output('', 'S');

        return $this->response
            ->setStatusCode(200)
            ->setContentType('application/pdf')
            ->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"')
            ->setBody($pdf);
    }

    public function sendWaOrtu()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $waService = new \App\Services\WhatsappService();
        if (!$waService->isConfigured()) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'WhatsApp belum dikonfigurasi. Silakan atur di Pengaturan WhatsApp.',
            ]);
        }

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif.']);
        }

        $classroomId = $this->request->getPost('classroom_id');
        $report = $this->tabunganModel->getReportByClass($activePeriod['id'], $classroomId);

        if (empty($report)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada data tabungan untuk dikirim.']);
        }

        $db = \Config\Database::connect();
        $userName = session()->get('user_name') ?? 'Petugas';

        $sent   = 0;
        $failed = 0;
        $skipped = 0;

        foreach ($report as $r) {
            $studentId = $r['student_id'];
            $student = $db->table('students')
                ->select('father_phone, mother_phone')
                ->where('id', $studentId)
                ->get()
                ->getRowArray();

            if (!$student) {
                $skipped++;
                continue;
            }

            $phone = $student['father_phone'] ?: $student['mother_phone'];
            if (empty($phone)) {
                $skipped++;
                continue;
            }

            $setoran   = number_format($r['total_setoran'], 0, ',', '.');
            $penarikan = number_format($r['total_penarikan'], 0, ',', '.');
            $saldo     = number_format($r['balance'], 0, ',', '.');

            $msg = "Assalamu'alaikum Wr. Wb.\n\n"
                . "Yth. Bapak/Ibu Wali dari *{$r['full_name']}*\n"
                . "Kelas: {$r['classroom_name']}\n\n"
                . "Berikut laporan tabungan siswa:\n"
                . "Periode: {$activePeriod['year_name']} / {$activePeriod['semester']}\n\n"
                . "💰 Total Setoran   : Rp {$setoran}\n"
                . "💸 Total Penarikan : Rp {$penarikan}\n"
                . "📊 Saldo Saat Ini  : Rp {$saldo}\n\n"
                . "Terima kasih.\n"
                . "_{$userName}_\n\n"
                . "--\n"
                . "Dikirim melalui SIMAK";

            try {
                $result = $waService->send($phone, $msg);
                if (is_array($result) && !empty($result['success'])) {
                    $sent++;
                } else {
                    $failed++;
                }
            } catch (\Exception $e) {
                $failed++;
            }

            usleep(500000);
        }

        return $this->response->setJSON([
            'success' => true,
            'message' => "Pengiriman selesai. Berhasil: {$sent}, Gagal: {$failed}, Dilewati: {$skipped}",
            'sent'    => $sent,
            'failed'  => $failed,
            'skipped' => $skipped,
        ]);
    }

    public function sendReport()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $waService = new \App\Services\WhatsappService();
        if (!$waService->isConfigured()) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'WhatsApp belum dikonfigurasi. Silakan atur di Pengaturan WhatsApp.',
            ]);
        }

        if (!$waService->isFeatureEnabled('tabungan')) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Fitur kirim laporan tabungan dinonaktifkan di pengaturan WhatsApp.',
            ]);
        }

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif.']);
        }

        $reportType = $this->request->getPost('report_type');
        $studentIds = $this->request->getPost('student_ids') ?? [];

        if (!is_array($studentIds)) {
            $studentIds = [$studentIds];
        }
        $studentIds = array_filter(array_map('intval', $studentIds));

        if (empty($studentIds)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada siswa yang dipilih.']);
        }

        $title       = '';
        $periodLabel = '';
        $reportData  = [];

        switch ($reportType) {
            case 'daily':
                $selectedDate = $this->request->getPost('report_date') ?: date('Y-m-d');
                if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $selectedDate)) {
                    return $this->response->setJSON(['success' => false, 'message' => 'Tanggal tidak valid.']);
                }
                $reportData  = $this->tabunganModel->getDailyReport($activePeriod['id'], $selectedDate, $studentIds);
                $title       = 'laporan tabungan harian';
                $periodLabel = date('d/m/Y', strtotime($selectedDate));
                break;

            case 'monthly':
                $month = $this->request->getPost('report_month') ?: date('Y-m');
                if (!preg_match('/^\d{4}-\d{2}$/', $month)) {
                    return $this->response->setJSON(['success' => false, 'message' => 'Bulan tidak valid.']);
                }
                [$year, $mon] = explode('-', $month);
                $reportData  = $this->tabunganModel->getMonthlyReport($activePeriod['id'], (int) $year, (int) $mon, $studentIds);
                $title       = 'laporan tabungan bulanan';
                $periodLabel = $this->bulanIndo((int) $mon) . ' ' . $year;
                break;

            case 'yearly':
                $periodId = (int) ($this->request->getPost('report_period_id') ?: $activePeriod['id']);
                $period   = null;
                foreach ($this->periodModel->getAllWithYear() as $p) {
                    if ((int) $p['id'] === $periodId) {
                        $period = $p;
                        break;
                    }
                }
                if (!$period) {
                    return $this->response->setJSON(['success' => false, 'message' => 'Periode tidak ditemukan.']);
                }
                $reportData  = $this->tabunganModel->getYearlyReport($periodId, $studentIds);
                $title       = 'laporan tabungan tahunan';
                $periodLabel = trim(($period['year_name'] ?? '') . ' — ' . ($period['semester'] ?? ''), ' —');
                break;

            default:
                return $this->response->setJSON(['success' => false, 'message' => 'Jenis laporan tidak valid.']);
        }

        if (empty($reportData)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada data siswa untuk dikirim.']);
        }

        $sent    = 0;
        $failed  = 0;
        $skipped = 0;
        $errors  = [];

        foreach ($reportData as $r) {
            $phone = trim($r['father_phone'] ?? '') ?: trim($r['mother_phone'] ?? '');
            if (empty($phone)) {
                $skipped++;
                continue;
            }

            $setoran   = number_format((float) $r['total_setoran'], 0, ',', '.');
            $penarikan = number_format((float) $r['total_penarikan'], 0, ',', '.');
            $saldo     = number_format((float) $r['balance'], 0, ',', '.');

            $msg = "Assalamu'alaikum Wr. Wb.\n"
                . "Yth. Bapak/Ibu Wali dari *{$r['full_name']}*\n\n"
                . "Berikut {$title}:\n"
                . "Tanggal: {$periodLabel}\n"
                . "Kelas: {$r['classroom_name']}\n\n"
                . "💰 Setoran: Rp {$setoran}\n"
                . "💸 Penarikan: Rp {$penarikan}\n"
                . "📊 Saldo: Rp {$saldo}\n\n"
                . "Terima kasih.\n"
                . "Yuk Menabung, untuk mempersiapkan kebutuhan masa depan\n"
                . "Wassalamualikum Wr. Wb.";

            try {
                $result = $waService->send($phone, $msg);
                if (is_array($result) && !empty($result['success'])) {
                    $sent++;
                } else {
                    $failed++;
                    $errors[] = $r['full_name'] . ': ' . ($result['message'] ?? 'Gagal kirim');
                }
            } catch (\Exception $e) {
                $failed++;
                $errors[] = $r['full_name'] . ': ' . $e->getMessage();
            }

            usleep(500000);
        }

        return $this->response->setJSON([
            'success' => true,
            'message' => "Pengiriman selesai. Berhasil: {$sent}, Gagal: {$failed}, Dilewati (no HP kosong): {$skipped}",
            'sent'    => $sent,
            'failed'  => $failed,
            'skipped' => $skipped,
            'errors'  => $errors,
        ]);
    }

    private function bulanIndo(int $bulan): string
    {
        $daftar = [
            1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April',
            5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus',
            9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember',
        ];
        return $daftar[$bulan] ?? '';
    }

    public function detail($studentId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $periodId = $this->request->getGet('period_id');
        $data     = $this->buildDetailData($studentId, $periodId);

        if (!$data) {
            return redirect()->to('/tabungan/report')->with('error', 'Siswa tidak ditemukan.');
        }

        $data['title']           = 'Detail Tabungan Siswa';
        $data['periods']         = $this->periodModel->getAllWithYear();
        $data['schoolSettings']  = $this->schoolSettingModel->first();
        $data['letterSettings']  = $this->getLetterSettings();
        $data['tabunganOfficerName'] = $this->getTabunganOfficerName();

        return view('tabungan/detail', $data);
    }

    public function printDetail($studentId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $periodId = $this->request->getGet('period_id');
        $data     = $this->buildDetailData($studentId, $periodId);

        if (!$data) {
            return redirect()->to('/tabungan/report')->with('error', 'Siswa tidak ditemukan.');
        }

        $data['schoolSettings']  = $this->schoolSettingModel->first();
        $data['letterSettings']  = $this->getLetterSettings();
        $data['tabunganOfficerName'] = $this->getTabunganOfficerName();

        $html = view('tabungan/print_detail', $data);

        $tempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
        if (!is_dir($tempDir)) {
            @mkdir($tempDir, 0777, true);
        }

        $mpdf = new \Mpdf\Mpdf([
            'tempDir'       => $tempDir,
            'margin_top'    => 10,
            'margin_bottom' => 10,
            'margin_left'   => 10,
            'margin_right'  => 10,
        ]);
        $mpdf->WriteHTML($html);

        $studentName = preg_replace('/[^A-Za-z0-9._-]+/', '-', $data['student']['full_name']);
        $filename = 'detail-tabungan-' . ($data['student']['nis'] ?: $studentId) . '-' . $studentName . '.pdf';

        $pdf = $mpdf->Output('', 'S');

        return $this->response
            ->setStatusCode(200)
            ->setContentType('application/pdf')
            ->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"')
            ->setBody($pdf);
    }

    private function buildDetailData($studentId, $periodId = null)
    {
        $student = $this->studentModel->find($studentId);
        if (!$student) {
            return null;
        }

        $activePeriod = $this->periodModel->getActive();
        if (!$periodId) {
            $periodId = $activePeriod['id'] ?? null;
        }

        $period = null;
        foreach ($this->periodModel->getAllWithYear() as $p) {
            if ((int) $p['id'] === (int) $periodId) {
                $period = $p;
                break;
            }
        }
        if (!$period) {
            $period = $activePeriod;
        }

        $db = \Config\Database::connect();
        $classroom = $db->table('student_academic_histories sah')
            ->select('c.name as classroom_name, g.name as grade_name')
            ->join('classrooms c', 'c.id = sah.classroom_id')
            ->join('grades g', 'g.id = c.grade_id')
            ->where('sah.student_id', $studentId)
            ->where('sah.academic_period_id', $period['id'])
            ->get()
            ->getRowArray();

        $transactions = $this->tabunganModel->getHistoryByPeriod($studentId, $period['id']);

        $totalSetoran   = 0;
        $totalPenarikan = 0;
        foreach ($transactions as $t) {
            if ($t['transaction_type'] === 'setoran') {
                $totalSetoran += (float) $t['amount'];
            } else {
                $totalPenarikan += (float) $t['amount'];
            }
        }

        $balance = 0;
        if (!empty($transactions)) {
            $last = end($transactions);
            $balance = (float) ($last['balance_after'] ?? 0);
        }

        return [
            'student'      => $student,
            'period'       => $period,
            'classroom'    => $classroom,
            'transactions' => $transactions,
            'totals'       => [
                'setoran'   => $totalSetoran,
                'penarikan' => $totalPenarikan,
                'balance'   => $balance,
            ],
            'tabunganOfficerName' => $this->getTabunganOfficerName(),
        ];
    }

    private function getTabunganOfficerName(): ?string
    {
        $setting = $this->schoolSettingModel->first();
        $teacherId = $setting['tabungan_officer_teacher_id'] ?? null;
        if (!$teacherId) {
            return null;
        }

        $teacher = (new TeacherModel())->find($teacherId);
        return $teacher['name'] ?? null;
    }

    private function getLetterSettings(): array
    {
        $settings = $this->schoolSettingModel->first();

        return [
            'kemenag_office'     => $settings['letter_kemenag_office'] ?? 'Kantor Kementerian Agama',
            'letter_school_name' => $settings['letter_school_name']
                ?? strtoupper($settings['school_name'] ?? 'MADRASAH'),
            'school_code'        => $settings['letter_school_code'] ?? 'MTs.11.22',
            'city'               => $settings['letter_city'] ?? $settings['city'] ?? 'Wonogiri',
            'logo_kemenag'       => $settings['logo_kemenag'] ?? 'logo_kemenag.png',
        ];
    }
}
