<?php

namespace App\Controllers;

use App\Models\ProfileModel;
use App\Models\MediaModel;
use App\Models\QRCodeModel;
use App\Models\SectionModel;
use App\Models\SectionItemModel;
use App\Models\SettingsModel;
use App\Libraries\FileUploadHandler;
use App\Libraries\QRCodeGenerator;

/**
 * MemberProfileController — lets a logged-in member edit their own profile.
 *
 * All write actions return JSON so the view can update the UI without reload.
 */
class MemberProfileController extends BaseController
{
    private ProfileModel      $profileModel;
    private MediaModel        $mediaModel;
    private QRCodeModel       $qrModel;
    private SectionModel      $sectionModel;
    private SectionItemModel  $sectionItemModel;
    private SettingsModel     $settingsModel;
    private FileUploadHandler $uploader;
    private QRCodeGenerator   $qrGenerator;

    public function __construct()
    {
        $this->profileModel      = new ProfileModel();
        $this->mediaModel        = new MediaModel();
        $this->qrModel           = new QRCodeModel();
        $this->sectionModel      = new SectionModel();
        $this->sectionItemModel  = new SectionItemModel();
        $this->settingsModel     = new SettingsModel();
        $this->uploader          = new FileUploadHandler();
        $this->qrGenerator       = new QRCodeGenerator();
    }

    // ----------------------------------------------------------------
    // Guard helper — returns profile array or redirects
    // ----------------------------------------------------------------
    private function guardMember(): ?array
    {
        $profileId = session()->get('member_profile_id');
        if (! $profileId) {
            return null;
        }
        return $this->profileModel->find($profileId);
    }

    // ----------------------------------------------------------------
    // GET /member/profile/edit
    // ----------------------------------------------------------------
    public function editPage()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return redirect()->to(site_url('member/login'));
        }

        $profileId = (int) $profile['id'];
        $gallery   = $this->mediaModel->getByProfile($profileId, 'gallery');
        $videos    = $this->mediaModel->getByProfile($profileId, 'video');
        $documents = $this->mediaModel->getByProfile($profileId, 'document');
        $qr        = $this->qrModel->getByProfile($profileId);
        $sections  = $this->sectionModel->getByProfile($profileId);

        // Fetch all items for all sections in one query, grouped by section_id
        $sectionIds   = array_column($sections, 'id');
        $sectionItems = $sectionIds
            ? $this->sectionItemModel->getBySections($sectionIds)
            : [];

        return view('member/edit', [
            'profile'      => $profile,
            'gallery'      => $gallery,
            'videos'       => $videos,
            'documents'    => $documents,
            'qr'           => $qr,
            'sections'     => $sections,
            'sectionItems' => $sectionItems,   // array keyed by section_id
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/save-theme  (AJAX JSON)
    // Saves the member's chosen colour theme to the profiles table
    // so it persists across sessions and devices.
    // ----------------------------------------------------------------
    public function saveTheme()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $allowed = ['sunset', 'ocean', 'forest', 'grape', 'coral'];
        $theme   = trim($this->request->getPost('theme') ?? '');

        if (! in_array($theme, $allowed, true)) {
            return $this->json(['success' => false, 'message' => 'Invalid theme.']);
        }

        $this->profileModel->update($profile['id'], ['theme' => $theme]);

        return $this->json(['success' => true, 'theme' => $theme]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/save-info  (AJAX JSON)
    // Saves: name, designation, company_name
    // ----------------------------------------------------------------
    public function saveInfo()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $name        = trim($this->request->getPost('name') ?? '');
        $designation = trim($this->request->getPost('designation') ?? '');
        $company     = trim($this->request->getPost('company_name') ?? '');

        if (empty($name)) {
            return $this->json(['success' => false, 'message' => 'Name is required.']);
        }

        $this->profileModel->update($profile['id'], [
            'name'        => $name,
            'designation' => $designation,
            'company_name'=> $company,
        ]);

        // Update session name
        session()->set('member_name', $name);

        return $this->json(['success' => true, 'message' => 'Profile info updated.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/save-about  (AJAX JSON)
    // ----------------------------------------------------------------
    public function saveAbout()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $about = trim($this->request->getPost('about_us') ?? '');
        $this->profileModel->update($profile['id'], ['about_us' => $about]);

        return $this->json(['success' => true, 'message' => 'About section updated.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/save-contact  (AJAX JSON)
    // ----------------------------------------------------------------
    public function saveContact()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $data = [
            'email'   => trim($this->request->getPost('email') ?? ''),
            'address' => trim($this->request->getPost('address') ?? ''),
            'website' => trim($this->request->getPost('website') ?? ''),
        ];

        // Validate email
        if (! empty($data['email']) && ! filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            return $this->json(['success' => false, 'message' => 'Invalid email address.']);
        }

        $this->profileModel->update($profile['id'], $data);

        return $this->json(['success' => true, 'message' => 'Contact info updated.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/save-social  (AJAX JSON)
    // ----------------------------------------------------------------
    public function saveSocial()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $this->profileModel->update($profile['id'], [
            'linkedin'  => trim($this->request->getPost('linkedin')  ?? ''),
            'instagram' => trim($this->request->getPost('instagram') ?? ''),
            'twitter'   => trim($this->request->getPost('twitter')   ?? ''),
            'facebook'  => trim($this->request->getPost('facebook')  ?? ''),
            'youtube'   => trim($this->request->getPost('youtube')   ?? ''),
        ]);

        return $this->json(['success' => true, 'message' => 'Social links updated.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/upload-photo  (multipart → AJAX JSON)
    // ----------------------------------------------------------------
    public function uploadPhoto()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $file = $this->request->getFile('photo');
        if (! $file || ! $file->isValid()) {
            return $this->json(['success' => false, 'message' => 'No file uploaded.']);
        }

        $result = $this->uploader->uploadImage($file, 'profiles');
        if (! $result['success']) {
            return $this->json(['success' => false, 'message' => $result['message']]);
        }

        // Delete old photo
        if (! empty($profile['profile_photo'])) {
            $this->uploader->deleteFile($profile['profile_photo']);
        }

        $this->profileModel->update($profile['id'], ['profile_photo' => $result['path']]);

        // Auto-regenerate QR code using the new photo as background (same as admin action)
        $qrUpdated = $this->regenerateQr((int) $profile['id'], $result['path']);

        // Build a cache-busted QR URL so the flip card immediately shows the new QR
        $qrUrl = null;
        if ($qrUpdated) {
            $qrUrl = base_url('uploads/qrcodes/qr_profile_' . $profile['id'] . '.png') . '?t=' . time();
        }

        return $this->json([
            'success'    => true,
            'url'        => base_url('uploads/' . $result['path']),
            'qr_updated' => $qrUpdated,
            'qr_url'     => $qrUrl,
            'message'    => 'Photo updated.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/upload-logo  (multipart → AJAX JSON)
    // ----------------------------------------------------------------
    public function uploadLogo()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $file = $this->request->getFile('logo');
        if (! $file || ! $file->isValid()) {
            return $this->json(['success' => false, 'message' => 'No file uploaded.']);
        }

        $result = $this->uploader->uploadImage($file, 'logos');
        if (! $result['success']) {
            return $this->json(['success' => false, 'message' => $result['message']]);
        }

        if (! empty($profile['company_logo'])) {
            $this->uploader->deleteFile($profile['company_logo']);
        }

        $this->profileModel->update($profile['id'], ['company_logo' => $result['path']]);

        return $this->json([
            'success' => true,
            'url'     => base_url('uploads/' . $result['path']),
            'message' => 'Logo updated.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/upload-gallery  (multipart → AJAX JSON)
    // ----------------------------------------------------------------
    public function uploadGallery()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $file = $this->request->getFile('image');
        if (! $file || ! $file->isValid()) {
            return $this->json(['success' => false, 'message' => 'No file uploaded.']);
        }

        $result = $this->uploader->uploadImage($file, 'gallery');
        if (! $result['success']) {
            return $this->json(['success' => false, 'message' => $result['message']]);
        }

        $id = $this->mediaModel->insert([
            'profile_id'    => $profile['id'],
            'media_type'    => 'gallery',
            'file_path'     => $result['path'],
            'original_name' => $file->getClientName(),
            'file_size'     => $file->getSize(),
            'mime_type'     => $file->getClientMimeType(),
            'sort_order'    => 0,
        ]);

        return $this->json([
            'success' => true,
            'id'      => $id,
            'url'     => base_url('uploads/' . $result['path']),
            'message' => 'Image uploaded.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/add-video  (AJAX JSON)
    // ----------------------------------------------------------------
    public function addVideo()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $url   = trim($this->request->getPost('url')   ?? '');
        $title = trim($this->request->getPost('title') ?? '');

        if (empty($url)) {
            return $this->json(['success' => false, 'message' => 'Video URL is required.']);
        }

        // Convert watch URL to embed URL
        $embedUrl = $this->toEmbedUrl($url);

        $id = $this->mediaModel->insert([
            'profile_id' => $profile['id'],
            'media_type' => 'video',
            'url'        => $embedUrl,
            'title'      => $title,
            'sort_order' => 0,
        ]);

        return $this->json([
            'success'  => true,
            'id'       => $id,
            'embedUrl' => $embedUrl,
            'title'    => $title,
            'message'  => 'Video added.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/upload-document  (multipart → AJAX JSON)
    // ----------------------------------------------------------------
    public function uploadDocument()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $file = $this->request->getFile('document');
        if (! $file || ! $file->isValid()) {
            return $this->json(['success' => false, 'message' => 'No file uploaded.']);
        }

        $result = $this->uploader->uploadMedia($file, 'documents');
        if (! $result['success']) {
            return $this->json(['success' => false, 'message' => $result['message']]);
        }

        $title = trim($this->request->getPost('title') ?? $file->getClientName());
        $id    = $this->mediaModel->insert([
            'profile_id'    => $profile['id'],
            'media_type'    => 'document',
            'file_path'     => $result['path'],
            'title'         => $title,
            'original_name' => $file->getClientName(),
            'file_size'     => $file->getSize(),
            'mime_type'     => $file->getClientMimeType(),
            'sort_order'    => 0,
        ]);

        $sizeFormatted = $this->formatBytes($file->getSize());

        return $this->json([
            'success'  => true,
            'id'       => $id,
            'title'    => $title,
            'size'     => $sizeFormatted,
            'url'      => base_url('uploads/' . $result['path']),
            'message'  => 'Document uploaded.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/delete-media/(:num)  (AJAX JSON)
    // ----------------------------------------------------------------
    public function deleteMedia(int $id)
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $media = $this->mediaModel->find($id);
        if (! $media || (int) $media['profile_id'] !== (int) $profile['id']) {
            return $this->json(['success' => false, 'message' => 'Not found.'], 404);
        }

        $this->mediaModel->deleteWithFile($id);

        return $this->json(['success' => true, 'message' => 'Deleted.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/add-section  (AJAX JSON)
    // Creates a custom section and inserts all initial items into
    // profile_section_items (for photo / video / document types).
    // Text sections store their content in profile_sections.content.
    // ----------------------------------------------------------------
    public function addSection()
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $type  = trim($this->request->getPost('section_type') ?? '');
        $title = trim($this->request->getPost('title')        ?? '');

        if (! in_array($type, ['text', 'photo', 'video', 'document'], true)) {
            return $this->json(['success' => false, 'message' => 'Invalid section type.']);
        }

        // Title is required for text; others get sensible defaults
        if ($type === 'text' && empty($title)) {
            return $this->json(['success' => false, 'message' => 'Section title is required.']);
        }
        if (empty($title)) {
            $title = match ($type) {
                'photo'    => 'Gallery',
                'video'    => 'Videos',
                'document' => 'Documents',
                default    => 'Section',
            };
        }

        $sectionData = [
            'profile_id'   => $profile['id'],
            'section_type' => $type,
            'title'        => $title,
            'sort_order'   => 0,
            'is_visible'   => 1,
        ];

        $response = ['success' => true, 'type' => $type, 'title' => $title, 'items' => []];

        // ── Text ──────────────────────────────────────────────────────────────
        if ($type === 'text') {
            $content = trim($this->request->getPost('content') ?? '');
            if (empty($content)) {
                return $this->json(['success' => false, 'message' => 'Content is required for a text section.']);
            }
            $sectionData['content'] = $content;
            $response['content']    = $content;
            $id = $this->sectionModel->insert($sectionData);
            $response['id']      = $id;
            $response['message'] = 'Text section added successfully.';
            return $this->json($response);
        }

        // ── Photo ─────────────────────────────────────────────────────────────
        if ($type === 'photo') {
            $files = $this->request->getFileMultiple('photos');
            if (empty($files) || ! $files[0]->isValid()) {
                return $this->json(['success' => false, 'message' => 'Please upload at least one photo.']);
            }
            $id = $this->sectionModel->insert($sectionData);
            foreach ($files as $file) {
                if (! $file->isValid()) continue;
                $result = $this->uploader->uploadImage($file, 'sections');
                if (! $result['success']) continue;
                $itemId = $this->sectionItemModel->insert([
                    'section_id'    => $id,
                    'file_path'     => $result['path'],
                    'original_name' => $file->getClientName(),
                    'file_size'     => $file->getSize(),
                    'mime_type'     => $file->getClientMimeType(),
                    'sort_order'    => 0,
                ]);
                $response['items'][] = [
                    'id'  => $itemId,
                    'url' => base_url('uploads/' . $result['path']),
                ];
            }
            if (empty($response['items'])) {
                $this->sectionModel->delete($id);
                return $this->json(['success' => false, 'message' => 'All photo uploads failed.']);
            }
            $response['id']      = $id;
            $response['message'] = 'Photo section added successfully.';
            return $this->json($response);
        }

        // ── Video ─────────────────────────────────────────────────────────────
        if ($type === 'video') {
            $rawUrls = $this->request->getPost('urls');     // array from urls[]
            if (! is_array($rawUrls)) {
                $rawUrls = $rawUrls ? [$rawUrls] : [];
            }
            $rawUrls = array_filter(array_map('trim', $rawUrls));
            if (empty($rawUrls)) {
                return $this->json(['success' => false, 'message' => 'Please enter at least one video URL.']);
            }
            $id = $this->sectionModel->insert($sectionData);
            foreach ($rawUrls as $rawUrl) {
                $embedUrl = $this->toEmbedUrl($rawUrl);
                $itemId   = $this->sectionItemModel->insert([
                    'section_id' => $id,
                    'url'        => $embedUrl,
                    'sort_order' => 0,
                ]);
                $response['items'][] = [
                    'id'       => $itemId,
                    'embedUrl' => $embedUrl,
                ];
            }
            $response['id']      = $id;
            $response['message'] = 'Video section added successfully.';
            return $this->json($response);
        }

        // ── Document ──────────────────────────────────────────────────────────
        if ($type === 'document') {
            $files = $this->request->getFileMultiple('documents');
            if (empty($files) || ! $files[0]->isValid()) {
                return $this->json(['success' => false, 'message' => 'Please upload at least one document.']);
            }
            $id = $this->sectionModel->insert($sectionData);
            foreach ($files as $file) {
                if (! $file->isValid()) continue;
                $result = $this->uploader->uploadMedia($file, 'sections');
                if (! $result['success']) continue;
                $itemId = $this->sectionItemModel->insert([
                    'section_id'    => $id,
                    'file_path'     => $result['path'],
                    'original_name' => $file->getClientName(),
                    'file_size'     => $file->getSize(),
                    'mime_type'     => $file->getClientMimeType(),
                    'sort_order'    => 0,
                ]);
                $response['items'][] = [
                    'id'       => $itemId,
                    'url'      => base_url('uploads/' . $result['path']),
                    'filename' => $file->getClientName(),
                    'size'     => $this->formatBytes($file->getSize()),
                ];
            }
            if (empty($response['items'])) {
                $this->sectionModel->delete($id);
                return $this->json(['success' => false, 'message' => 'All document uploads failed.']);
            }
            $response['id']      = $id;
            $response['message'] = 'Document section added successfully.';
            return $this->json($response);
        }

        return $this->json(['success' => false, 'message' => 'Unknown section type.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/add-section-item/(:num)  (AJAX JSON)
    // Adds one or more items to an existing section.
    // ----------------------------------------------------------------
    public function addSectionItem(int $sectionId)
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $section = $this->sectionModel->find($sectionId);
        if (! $section || (int) $section['profile_id'] !== (int) $profile['id']) {
            return $this->json(['success' => false, 'message' => 'Section not found.'], 404);
        }

        $type     = $section['section_type'];
        $newItems = [];

        if ($type === 'photo') {
            $files = $this->request->getFileMultiple('photos');
            if (empty($files) || ! $files[0]->isValid()) {
                return $this->json(['success' => false, 'message' => 'No photos uploaded.']);
            }
            foreach ($files as $file) {
                if (! $file->isValid()) continue;
                $result = $this->uploader->uploadImage($file, 'sections');
                if (! $result['success']) continue;
                $itemId = $this->sectionItemModel->insert([
                    'section_id'    => $sectionId,
                    'file_path'     => $result['path'],
                    'original_name' => $file->getClientName(),
                    'file_size'     => $file->getSize(),
                    'mime_type'     => $file->getClientMimeType(),
                    'sort_order'    => 0,
                ]);
                $newItems[] = [
                    'id'  => $itemId,
                    'url' => base_url('uploads/' . $result['path']),
                ];
            }
        } elseif ($type === 'video') {
            $rawUrls = $this->request->getPost('urls');
            if (! is_array($rawUrls)) {
                $rawUrls = $rawUrls ? [$rawUrls] : [];
            }
            $rawUrls = array_filter(array_map('trim', $rawUrls));
            if (empty($rawUrls)) {
                return $this->json(['success' => false, 'message' => 'No video URLs provided.']);
            }
            foreach ($rawUrls as $rawUrl) {
                $embedUrl = $this->toEmbedUrl($rawUrl);
                $itemId   = $this->sectionItemModel->insert([
                    'section_id' => $sectionId,
                    'url'        => $embedUrl,
                    'sort_order' => 0,
                ]);
                $newItems[] = ['id' => $itemId, 'embedUrl' => $embedUrl];
            }
        } elseif ($type === 'document') {
            $files = $this->request->getFileMultiple('documents');
            if (empty($files) || ! $files[0]->isValid()) {
                return $this->json(['success' => false, 'message' => 'No documents uploaded.']);
            }
            foreach ($files as $file) {
                if (! $file->isValid()) continue;
                $result = $this->uploader->uploadMedia($file, 'sections');
                if (! $result['success']) continue;
                $itemId = $this->sectionItemModel->insert([
                    'section_id'    => $sectionId,
                    'file_path'     => $result['path'],
                    'original_name' => $file->getClientName(),
                    'file_size'     => $file->getSize(),
                    'mime_type'     => $file->getClientMimeType(),
                    'sort_order'    => 0,
                ]);
                $newItems[] = [
                    'id'       => $itemId,
                    'url'      => base_url('uploads/' . $result['path']),
                    'filename' => $file->getClientName(),
                    'size'     => $this->formatBytes($file->getSize()),
                ];
            }
        } else {
            return $this->json(['success' => false, 'message' => 'Text sections have no items.']);
        }

        if (empty($newItems)) {
            return $this->json(['success' => false, 'message' => 'No items were added.']);
        }

        return $this->json([
            'success'    => true,
            'section_id' => $sectionId,
            'type'       => $type,
            'items'      => $newItems,
            'message'    => count($newItems) . ' item(s) added.',
        ]);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/delete-section-item/(:num)  (AJAX JSON)
    // Deletes a single item from a section.
    // ----------------------------------------------------------------
    public function deleteSectionItem(int $itemId)
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $item = $this->sectionItemModel->find($itemId);
        if (! $item) {
            return $this->json(['success' => false, 'message' => 'Item not found.'], 404);
        }

        // Verify ownership via parent section
        $section = $this->sectionModel->find($item['section_id']);
        if (! $section || (int) $section['profile_id'] !== (int) $profile['id']) {
            return $this->json(['success' => false, 'message' => 'Item not found.'], 404);
        }

        $this->sectionItemModel->deleteWithFile($itemId);

        return $this->json(['success' => true, 'message' => 'Item deleted.']);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/update-section/(:num)  (AJAX JSON)
    // For text:     updates title + content.
    // For others:   updates title only (items are managed separately).
    // ----------------------------------------------------------------
    public function updateSection(int $id)
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $section = $this->sectionModel->find($id);
        if (! $section || (int) $section['profile_id'] !== (int) $profile['id']) {
            return $this->json(['success' => false, 'message' => 'Section not found.'], 404);
        }

        $type  = $section['section_type'];
        $title = trim($this->request->getPost('title') ?? '');

        if (empty($title)) {
            if ($type === 'text') {
                return $this->json(['success' => false, 'message' => 'Section title is required.']);
            }
            $title = $section['title'];
        }

        $updateData = ['title' => $title];
        $response   = ['success' => true, 'id' => $id, 'type' => $type, 'title' => $title];

        if ($type === 'text') {
            $content = trim($this->request->getPost('content') ?? '');
            if (empty($content)) {
                return $this->json(['success' => false, 'message' => 'Content is required.']);
            }
            $updateData['content'] = $content;
            $response['content']   = $content;
        }
        // For photo / video / document: only title is updated here.
        // Individual items are managed via addSectionItem / deleteSectionItem.

        $this->sectionModel->update($id, $updateData);
        $response['message'] = 'Section updated successfully.';

        return $this->json($response);
    }

    // ----------------------------------------------------------------
    // POST /member/profile/delete-section/(:num)  (AJAX JSON)
    // Deletes the section and all its items.
    // ----------------------------------------------------------------
    public function deleteSection(int $id)
    {
        $profile = $this->guardMember();
        if (! $profile) {
            return $this->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }

        $section = $this->sectionModel->find($id);
        if (! $section || (int) $section['profile_id'] !== (int) $profile['id']) {
            return $this->json(['success' => false, 'message' => 'Section not found.'], 404);
        }

        // Cascade-delete all items (with their files on disk)
        $this->sectionItemModel->deleteAllForSection($id);
        $this->sectionModel->delete($id);

        return $this->json(['success' => true, 'message' => 'Section deleted.']);
    }

    // ----------------------------------------------------------------
    // Private helpers
    // ----------------------------------------------------------------

    /**
     * Regenerate the QR code for a profile using the new photo as the
     * dot-style background — mirrors Admin\QRCodeController::generate().
     *
     * @param int    $profileId
     * @param string $newPhotoRelPath  e.g. 'profiles/abc123.jpg'
     */
    private function regenerateQr(int $profileId, string $newPhotoRelPath): bool
    {
        try {
            $profile = $this->profileModel->find($profileId);
            if (! $profile) {
                return false;
            }

            // Resolve the public QR URL — same priority as admin controller
            $envBase     = env('qr.baseURL');
            $settingBase = $this->settingsModel->getSetting('qr_base_url');

            if (! empty($envBase)) {
                $qrUrl = rtrim($envBase, '/') . '/' . $profile['slug'];
            } elseif (! empty($settingBase)) {
                $qrUrl = rtrim($settingBase, '/') . '/' . $profile['slug'];
            } else {
                $req      = service('request');
                $scheme   = $req->isSecure() ? 'https' : 'http';
                $host     = $req->getServer('HTTP_HOST');
                $basePath = rtrim(dirname($req->getServer('SCRIPT_NAME'), 2), '/\\');
                $qrUrl    = $scheme . '://' . $host . $basePath . '/profile/' . $profile['slug'];
            }

            // Absolute path to the newly uploaded photo
            $photoPath = null;
            $candidate = FCPATH . 'uploads/' . ltrim($newPhotoRelPath, '/');
            if (file_exists($candidate)) {
                $photoPath = $candidate;
            }

            // Ensure QR output directory exists
            $qrDir = FCPATH . 'uploads/qrcodes/';
            if (! is_dir($qrDir)) {
                mkdir($qrDir, 0775, true);
            }

            $savePath = $qrDir . 'qr_profile_' . $profileId . '.png';

            $this->qrGenerator->generate([
                'data'       => $qrUrl,
                'save_path'  => $savePath,
                'photo_path' => $photoPath,
                'foreground' => '#000000',
                'background' => '#FFFFFF',
                'size'       => 1200,
                'margin'     => 0,
            ]);

            $this->qrModel->upsert($profileId, [
                'file_path'  => 'qrcodes/qr_profile_' . $profileId . '.png',
                'qr_url'     => $qrUrl,
                'has_logo'   => 0,
                'logo_path'  => null,
                'foreground' => '#000000',
                'background' => '#FFFFFF',
            ]);

            return true;

        } catch (\Throwable $e) {
            log_message('error', '[MemberProfile] QR auto-regen failed for profile #' . $profileId . ': ' . $e->getMessage());
            return false;
        }
    }

    /** Return a JSON response — always injects the refreshed CSRF hash so JS
     *  can update its token after each request (CI4 rotates the hash). */
    private function json(array $data, int $status = 200): \CodeIgniter\HTTP\ResponseInterface
    {
        // Attach the new CSRF hash so the client can refresh its copy
        $data[csrf_token()] = csrf_hash();

        return $this->response
            ->setStatusCode($status)
            ->setContentType('application/json')
            ->setJSON($data);
    }

    /** Convert YouTube/Vimeo watch URLs to embed URLs */
    private function toEmbedUrl(string $url): string
    {
        // YouTube watch URL → embed
        if (preg_match('/(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $url, $m)) {
            return 'https://www.youtube.com/embed/' . $m[1] . '?controls=1';
        }
        // Vimeo
        if (preg_match('/vimeo\.com\/(\d+)/', $url, $m)) {
            return 'https://player.vimeo.com/video/' . $m[1];
        }
        // Already an embed or unknown — return as-is
        return $url;
    }

    private function formatBytes(int $bytes): string
    {
        if ($bytes >= 1048576) {
            return round($bytes / 1048576, 1) . ' MB';
        }
        return round($bytes / 1024, 0) . ' KB';
    }
}
