<?php

namespace Mtc\Plugins\Clinic\Http\Controllers\Admin;

use App\Src\Encryption;
use Carbon\Carbon;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\DB;
use Mtc\Modules\Members\Classes\MemberManager;
use Mtc\Modules\Members\Models\Member;
use Mtc\Modules\Members\Models\MemberAttribute;
use Mtc\Plugins\Clinic\Src\Services\PatientProfileBootstrapService;
use Mtc\Plugins\NewsletterSignup\Classes\Newsletter;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Pagination\UrlWindow;
use Illuminate\Support\Str;

class PatientController extends ClinicController
{
    public function __construct(private readonly PatientProfileBootstrapService $bootstrapService)
    {
        parent::__construct();
    }

    /**
     * List of patients
     */


    public function index(Request $request)
    {

        $allowed  = [20, 40, 60, 80, 100, 250];
        $perPage  = (int) $request->query('per_page', 20);
        if (!in_array($perPage, $allowed, true)) $perPage = 20;

        $patients = Member::query()
            ->with(['addressBilling' => fn($q) => $q->select('id','member_id','firstname','lastname')])
            ->select('id','email','contact_no','dob')
            ->orderByDesc('id');

        $patients = self::filterPatients($patients, $request->all())
            ->paginate($perPage)                        // <-- numbered pages
            ->appends($request->all())
            ->appends(['per_page' => $perPage]);

        // Build the page number window (e.g. 1 … 8 9 [10] 11 12 … 99)
        $paginationElements = array_filter(UrlWindow::make($patients)); // returns array, not object

        $payload = [
            'patients'           => $patients,
            'paginationElements' => $paginationElements ?? [],
            'perPage'            => $perPage,
            'request'            => $request->all(),
            'paginated'            => true,
            'showNewsletterFilter' => Newsletter::isDefaultDriver(),
        ];

        // Only return partial for real AJAX (X-Requested-With) + explicit flag
        if ($request->ajax() && $request->boolean('_partial')) {
            return template('admin/patients/_ajax_wrapper.twig', $payload);
        }

        // Full admin view on hard refresh / direct URL hits
        $payload['page_meta']['title'] = config('app.name').' | Manage Patients';
        $payload['title'] = 'Manage Patients';
        return template('admin/patients/index.twig', $payload);
    }




    /**
     * Export patients CSV
     */
    public function export(Request $request): StreamedResponse
    {
        $query = Member::query()
            ->select('members.id','members.email','members.contact_no',
                'members.allergies','members.medications','members.conditions')
            ->leftJoin('members_addresses as a', function ($j) {
                $j->on('a.member_id','=','members.id')->where('a.type','=','billing');
            })
            ->addSelect('a.firstname','a.lastname','a.address1','a.address2','a.city','a.country','a.postcode');

        $query = self::filterPatients($query, $request->all())->orderBy('members.id');

        $headers = [
            'Content-Type'        => 'text/csv',
            'Content-Disposition' => 'attachment; filename="patients.csv"',
            'Cache-Control'       => 'no-store, no-cache',
        ];

        $columns = [
            'Patient ID','Firstname','Lastname','Email','Contact No','Allergies',
            'Medications','Medical Conditions','Address 1','Address 2','City','Country','Postcode',
        ];

        return response()->stream(function() use ($query, $columns) {
            $out = fopen('php://output', 'w');
            // Excel-friendly UTF-8 BOM (optional)
            fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
            fputcsv($out, $columns);

            $query->chunkById(2000, function($rows) use ($out) {
                foreach ($rows as $r) {
                    $meds = $r->medications ? implode(', ', (array) json_decode($r->medications, true)) : '';
                    $conds = $r->conditions ? implode(', ', (array) json_decode($r->conditions, true)) : '';

                    fputcsv($out, [
                        $r->id,
                        $r->firstname,
                        $r->lastname,
                        $r->email,
                        $r->contact_no,
                        $r->allergies,
                        $meds,
                        $conds,
                        $r->address1,
                        $r->address2,
                        $r->city,
                        $r->country,
                        $r->postcode,
                    ]);
                }
                // flush each chunk
                fflush($out);
            });

            fclose($out);
        }, 200, $headers);
    }

    /**
     * Add a patients
     */
    public function add(Request $request): string
    {
        $title = 'Create a patient';
        $page_meta['title'] = config('app.name') . ' | ' . $title;

        return template('admin/patients/add.twig', [
            'page_meta' => $page_meta,
            'title' => $title,
            'request' => $request->all(),
        ]);
    }

    /**
     * Add a patients
     */
    public function profile($id, Request $request): string
    {
        /** @var Member $patient */
        $patient = Member::query()
            ->with('addressBilling')
            ->with('addressShipping')
            ->findOrFail($id);

        $title = $patient->addressBilling->firstname . ' ' . $patient->addressBilling->lastname;
        $page_meta['title'] = config('app.name') . ' | ' . $title;

        $patient->dob = $patient->getDob();
        $patient->age = $patient->getAge();

        $patient->weight = '-';
        $patient->bmi = '-';
        $patient->progress = [];

        $patient->doctor_surgery = !empty($patient->doctor_surgery) ?
            json_decode($patient->doctor_surgery) :
            null;

        $weightTrack = $patient->weightTrack()
            ->orderByDesc('date_provided')
            ->first();

        if (!empty($weightTrack)) {
            $patient->weight = $weightTrack->weight;
            $patient->bmi = $weightTrack->bmi;

            $firstWeightTrack = $patient->weightTrack()
                ->orderBy('date_provided')
                ->first();

            if (!empty($firstWeightTrack)) {
                $difference = $patient->weight - $firstWeightTrack->weight;
                $patient->progress = [
                    'reduction' => $difference,
                    'reduction_percent' => round($difference / $firstWeightTrack->weight * 100),
                ];
            }
        }

        $routes = $this->patientRoutes($id);
        $bootstrap = $this->bootstrapService->build($id);
        $bootstrap['routes'] = $routes;

        return template('admin/patients/profile.twig', [
            'page_meta' => $page_meta,
            'title' => $title,
            'patient' => $patient,
            'attributes' => MemberAttribute::getFields(),
            'routes' => $routes,
            'profileBootstrap' => $bootstrap,
            'request' => $request->all(),
        ]);
    }

    /**
     * Search patients
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function search(Request $request)
    {
        // per-page handling (same as index)
        $allowed  = [20, 40, 60, 80, 100, 250];
        $perPage  = (int) $request->query('per_page', 20);
        if (!in_array($perPage, $allowed, true)) $perPage = 20;

        // base query (QUALIFY columns to avoid ambiguity after JOINs)
        $patients = Member::query()
            ->with(['addressBilling' => fn($q) => $q->select('id','member_id','firstname','lastname')])
            ->select('members.id','members.email','members.contact_no','members.dob')
            ->orderByDesc('members.id');

        // same filters
        $patients = self::filterPatients($patients, $request->all())
            ->paginate($perPage)
            // make sure pager links stay under /admin/patients/search
            ->withPath(route('admin-patients-search'))
            ->appends($request->all())
            ->appends(['per_page' => $perPage]);

        // page number window
        $paginationElements = array_filter(UrlWindow::make($patients));

        // shared payload
        $payload = [
            'patients'             => $patients,
            'paginationElements'   => $paginationElements ?? [],
            'perPage'              => $perPage,
            'request'              => $request->all(),
            'paginated'            => true,
            'showNewsletterFilter' => Newsletter::isDefaultDriver(),
        ];

        // AJAX partial (used by your JS)
        if ($request->ajax() && $request->boolean('_partial')) {
            return template('admin/patients/_ajax_wrapper.twig', $payload);
        }

        // Full admin view on hard refresh / direct URL hits
        $payload['page_meta']['title'] = config('app.name').' | Manage Patients';
        $payload['title'] = 'Manage Patients';

        return template('admin/patients/index.twig', $payload);
    }




    public static function filterPatients(Builder $query, array $filters): Builder
    {
        if (!empty($filters['id'])) {
            $query->where('members.id', (int) $filters['id']);
        }

        if (!empty($filters['email'])) {
            $raw   = trim((string) $filters['email']);
            $lower = \Illuminate\Support\Str::lower($raw);
            // we support both raw and lower-case variants in case history data was hashed differently
            $variants = array_values(array_unique([$raw, $lower]));
            $hashes   = array_map(fn($v) => \App\Src\Encryption::makeHash($v), $variants);

            // compare ONLY against the hash column
            $query->whereIn('members.email_hash', $hashes);
        }

        if (!empty($filters['contact_no'])) {
            $raw    = trim((string) $filters['contact_no']);
            $digits = preg_replace('/\D+/', '', $raw) ?? '';
            $variants = array_values(array_unique([$raw, $digits]));
            $hashes   = array_map(fn($v) => \App\Src\Encryption::makeHash($v), $variants);

            $query->whereIn('members.contact_no_hash', $hashes);
        }

        if (!empty($filters['date_of_birth'])) {
            try {
                $dob = \Carbon\Carbon::createFromFormat('d/m/Y', $filters['date_of_birth'])->format('Y-m-d');
                $query->where('members.dob_hash', \App\Src\Encryption::makeHash($dob));
            } catch (\Exception) {}
        }

        // Firstname / Lastname (exact by *_hash on billing address)
        if (!empty($filters['firstname']) || !empty($filters['lastname'])) {
            $query->leftJoin('members_addresses as ab', function($j) {
                $j->on('ab.member_id','=','members.id')->where('ab.type','=','billing');
            });

            $query->where(function($w) use ($filters) {
                if (!empty($filters['firstname'])) {
                    $w->where('ab.firstname_hash', \App\Src\Encryption::makeHash(trim($filters['firstname'])));
                }
                if (!empty($filters['lastname'])) {
                    $w->where('ab.lastname_hash',  \App\Src\Encryption::makeHash(trim($filters['lastname'])));
                }
            });
        }

        // Keep newsletter filter as you had it (plaintext list table)
        if (!empty($filters['newsletter'])) {
            if ($filters['newsletter'] === 'yes') {
                $query->whereExists(function ($q) {
                    $q->select(\DB::raw(1))
                        ->from('emails_lists_mails')
                        ->whereRaw('emails_lists_mails.email = members.email');
                });
            } elseif ($filters['newsletter'] === 'no') {
                $query->whereNotExists(function ($q) {
                    $q->select(\DB::raw(1))
                        ->from('emails_lists_mails')
                        ->whereRaw('emails_lists_mails.email = members.email');
                });
            }
        }

        // Optional: if firstname/lastname join might create duplicates, de-dupe
        $query->distinct('members.id');

        return $query;
    }






    /**
     * Login as member
     *
     * @param $id
     * @return Application|RedirectResponse|Redirector
     */
    public function loginAs($id): Redirector|RedirectResponse|Application
    {
        MemberManager::loginAsMember($id);
        return redirect(route('members-dashboard'));
    }


    /**
     * Get patient routes
     *
     * @param $id
     * @return array
     */
    public function patientRoutes($id): array
    {
        return [
            'admin-member-attributes-load' => route('admin-member-attributes-load', [
                'id' => $id,
            ]),
            'admin-member-attributes-store' => route('admin-member-attributes-store', [
                'id' => $id,
            ]),
            'admin-member-notes-load' => route('admin-member-notes-load', [
                'id' => $id,
            ]),
            'admin-member-notes-store' => route('admin-member-notes-store', [
                'id' => $id,
            ]),
            'admin-member-notes-load-flags' => route('admin-member-notes-load-flags', [
                'id' => $id,
            ]),
            'admin-member-notes-delete-flag' => route('admin-member-notes-delete-flag', [
                'id' => $id,
            ]),
            'admin-member-notes-toggle-flag-status' => route('admin-member-notes-toggle-flag-status', [
                'id' => $id,
            ]),
            'admin-member-orders-load' => route('admin-member-orders-load', [
                'id' => $id,
            ]),
            'admin-reviews-load' => route('admin-reviews-load', [
                'member_id' => $id,
            ]),
            'admin-reviews-load-review' => route('admin-reviews-load-review'),
            'admin-member-orders-add' => '/plugins/BasketBuilder/admin/add.php?' . http_build_query([
                'member_id' => $id,
                ]),
            'admin-patient-treatments-load' => route('admin-patient-treatments-load', [
                'id' => $id,
            ]),
            'admin-patient-treatments-store' => route('admin-patient-treatments-store', [
                'id' => $id,
            ]),
            'admin-patient-treatments-delete' => route('admin-patient-treatments-delete', [
                'id' => $id,
            ]),
            'admin-products-search' => route('admin-products-search'),
            'admin-patient-bp-track-load' => route('admin-patient-bp-track-load', [
                'id' => $id,
            ]),
            'admin-patient-bp-track-store' => route('admin-patient-bp-track-store', [
                'id' => $id,
            ]),
            'admin-patient-bp-track-delete' => route('admin-patient-bp-track-delete', [
                'id' => $id,
            ]),
            'admin-patient-weight-track-load' => route('admin-patient-weight-track-load', [
                'id' => $id,
            ]),
            'admin-patient-weight-track-store' => route('admin-patient-weight-track-store', [
                'id' => $id,
            ]),
            'admin-patient-weight-track-delete' => route('admin-patient-weight-track-delete', [
                'id' => $id,
            ]),
            'admin-patient-files-load' => route('admin-patient-files-load', [
                'id' => $id,
            ]),
            'admin-patient-files-store' => route('admin-patient-files-store', [
                'id' => $id,
            ]),
            'admin-patient-files-delete' => route('admin-patient-files-delete', [
                'id' => $id,
            ]),
            'admin-patient-consultations-load' => route('admin-patient-consultations-load', [
                'id' => $id,
            ]),
            'admin-patient-messages-load' => route('admin-patient-messages-load', [
                'id' => $id,
            ]),
            'admin-patient-event-log-load' => route('admin-patient-event-log-load', [
                'id' => $id,
            ]),
            'admin-reviews-store' => route('admin-reviews-store'),
            'admin-patients-profile' => route('admin-patients-profile', [
                'id' => '---id---',
            ]),
            'admin-patient-profile-bootstrap' => route('admin-patient-profile-bootstrap', ['id' => $id]),
            'edit-patient' => '/modules/Members/admin/manage_member.php?id=' . $id,
            'admin-patient-messages-create-thread' => '/plugins/MembersMessaging/admin/view_member_thread.php?act=request_info&member_id=' . $id,
        ];
    }
}
