<?php
// ====================================================
// PART 1: PHP Header + HTML Template
// ====================================================
use yii\helpers\Url;

$this->title = 'Car Administration';

$baseUrl      = Yii::$app->request->baseUrl;
$uploadUrl    = $baseUrl . '/uploads/cars/';
$defaultThumb = $baseUrl . '/uploads/cars/default.jpg';
$saveUrl      = Url::to(['car/save-ajax']);
$deleteUrl    = Url::to(['car/delete']);
$viewUrl      = Url::to(['car/view']);
?>

<script>
window.CarAppData = {
    cars:         <?= json_encode($cars,         JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP|JSON_UNESCAPED_UNICODE) ?>,
    totalCount:   <?= $totalCount ?>,
    statusCounts: <?= json_encode($statusCounts, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) ?>,
    clients:      <?= json_encode($clients,      JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP|JSON_UNESCAPED_UNICODE) ?>,
    auctions:     <?= json_encode($auctions,     JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP|JSON_UNESCAPED_UNICODE) ?>,
    warehouses:   <?= json_encode($warehouses,   JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP|JSON_UNESCAPED_UNICODE) ?>,
    destinations: <?= json_encode($destinations, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP|JSON_UNESCAPED_UNICODE) ?>,
    saveUrl:       '<?= $saveUrl ?>',
    deleteUrl:     '<?= $deleteUrl ?>',
    viewUrl:       '<?= $viewUrl ?>',
    uploadBaseUrl: '<?= $uploadUrl ?>',
    defaultThumb:  '<?= $defaultThumb ?>',
    csrfToken:     '<?= Yii::$app->request->csrfToken ?>',
    csrfParam:     '<?= Yii::$app->request->csrfParam ?>',
};
</script>

<div id="carApp" class="container-fluid pt-4" v-cloak>

    <!-- Global Loading Overlay -->
    <div v-if="loading"
         style="position:fixed;top:0;left:0;width:100%;height:100%;
                background:rgba(255,255,255,0.82);z-index:9998;
                display:flex;flex-direction:column;
                align-items:center;justify-content:center;
                backdrop-filter:blur(2px);">
        <div class="spinner-border text-primary mb-3"
             style="width:3rem;height:3rem;" role="status"></div>
        <div class="fw-semibold text-primary">Processing, please wait...</div>
        <div class="mt-3" style="width:260px;">
            <div class="progress rounded-pill" style="height:6px;">
                <div class="progress-bar progress-bar-striped progress-bar-animated bg-primary"
                     style="width:100%"></div>
            </div>
        </div>
    </div>

    <!-- Page Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h4 class="fw-bold mb-0 text-dark">
                <i class="bi bi-car-front-fill text-primary me-2"></i>Vehicle Inventory
            </h4>
            <p class="text-muted small mb-0 mt-1">
                Manage all vehicles, photos, and logistics information.
            </p>
        </div>
        <button @click="openModal()"
                class="btn btn-primary rounded-pill px-4 shadow-sm fw-semibold">
            <i class="bi bi-plus-circle-fill me-2"></i> Add New Vehicle
        </button>
    </div>

    <!-- Stats Row -->
    <div class="row g-3 mb-4">
        <div class="col-6 col-md-2" v-for="stat in statusStats" :key="stat.status">
            <div class="card border-0 shadow-sm rounded-4 h-100">
                <div class="card-body py-3 px-3 text-center">
                    <div class="fw-bold fs-4 text-dark">{{ stat.count }}</div>
                    <div class="small text-muted mb-1">{{ stat.label }}</div>
                    <span :class="stat.badge" class="badge rounded-pill"
                          style="font-size:0.65rem;">{{ stat.status }}</span>
                </div>
            </div>
        </div>
    </div>

    <!-- Search Bar -->
    <div class="card mb-4 border-0 shadow-sm rounded-4 overflow-hidden">
        <div class="card-body p-0 d-flex align-items-center">
            <div class="ps-4 text-muted">
                <i v-if="!searchQuery" class="bi bi-search fs-5"></i>
                <i v-else @click="searchQuery=''; currentPage=1; fetchPage(1);"
                   class="bi bi-x-circle-fill fs-5 text-danger"
                   style="cursor:pointer" title="Clear"></i>
            </div>
            <input type="text"
                   id="carSearchInput"
                   name="car_search"
                   autocomplete="off"
                   v-model="searchQuery"
                   @input="onSearchInput"
                   placeholder="Search by VIN, Lot, Info, Container, Status, Client No/Name/Phone..."
                   class="form-control form-control-lg border-0 shadow-none py-3 ps-3">
            <div class="pe-4 text-muted small text-nowrap">
                <strong>{{ totalCount }}</strong> result(s)
            </div>
        </div>
    </div>

    <!-- Table Card -->
    <div class="card border-0 shadow-sm rounded-4 overflow-hidden">
        <div class="table-responsive">
            <table class="table table-hover align-middle mb-0" style="font-size:0.855rem;">
                <thead class="bg-light">
                    <tr class="text-nowrap small text-muted">
                        <th class="ps-4">#</th>
                        <th>PHOTO</th>
                        <th>YEAR</th>
                        <th>VIN</th>
                        <th>VEHICLE INFO</th>
                        <th>PURCHASE DATE</th>
                        <th>AUCTION</th>
                        <th>TITLE/KEY</th>
                        <th>LOT</th>
                        <th>PRICE</th>
                        <th>CLIENT</th>
                        <th>NOTE</th>
                        <th>CONTAINER</th>
                        <th>ETA</th>
                        <th>WAREHOUSE</th>
                        <th>STATUS</th>
                        <th>LINER</th>
                        <th class="text-end pe-4">ACTIONS</th>
                    </tr>
                </thead>
                <tbody class="bg-white">
                    <tr v-if="cars.length === 0">
                        <td colspan="18" class="text-center py-5 text-muted">
                            <i class="bi bi-inbox fs-2 d-block mb-2"></i>
                            <span v-if="searchQuery">
                                No results for <strong>"{{ searchQuery }}"</strong>
                            </span>
                            <span v-else>
                                No vehicles yet. Click <strong>Add New Vehicle</strong>.
                            </span>
                        </td>
                    </tr>
                    <tr v-for="(car, index) in cars" :key="car.id">

                        <td class="ps-4 text-muted small">
                            {{ ((currentPage - 1) * pageSize) + index + 1 }}
                        </td>

                        <td>
                            <img :src="car.thumbnail
                                        ? uploadBaseUrl + car.thumbnail
                                        : defaultThumb"
                                 width="60" height="44"
                                 class="rounded-2 border object-fit-cover shadow-sm"
                                 @error="onTableImgError($event)">
                        </td>

                        <td class="fw-bold">{{ car.year || '—' }}</td>

                        <td class="fw-semibold text-nowrap">{{ car.vin || '—' }}</td>

                        <td style="max-width:160px;">
                            <div class="text-truncate" :title="car.info">{{ car.info || '—' }}</div>
                        </td>

                        <td class="text-nowrap">{{ formatDate(car.purchase_date) }}</td>

                        <td class="fw-semibold text-nowrap">{{ getAuctionName(car.auction_id) }}</td>

                        <td>
                            <span class="badge bg-light text-dark border rounded-pill">
                                {{ car.title || 'No Title' }}
                            </span>
                        </td>

                        <td class="fw-semibold">{{ car.lot }}</td>

                        <td class="fw-bold text-nowrap">${{ formatNumber(car.price) }}</td>

                        <td class="text-nowrap">
                            <span class="badge bg-secondary-subtle text-secondary border me-1 rounded-pill">
                                {{ getClientNo(car.client_id) }}
                            </span>
                            {{ getClientName(car.client_id) }}
                        </td>

                        <td style="max-width:130px;">
                            <div class="text-danger small fst-italic text-truncate" :title="car.note">
                                {{ car.note || '' }}
                            </div>
                        </td>

                        <td class="fw-semibold text-nowrap">{{ car.container || '—' }}</td>

                        <td class="text-nowrap">{{ formatDate(car.eta_date) }}</td>

                        <td class="text-nowrap">{{ getWarehouseName(car.warehouse_id) }}</td>

                        <td>
                            <span :class="getStatusBadge(car.status)"
                                  class="badge rounded-pill px-3 py-2">
                                {{ formatStatus(car.status) }}
                            </span>
                        </td>

                        <td class="text-nowrap">
                            <div class="fw-semibold small">{{ car.liner || '—' }}</div>
                            <a v-if="car.shipping_line"
                               :href="car.shipping_line" target="_blank"
                               class="small text-primary text-decoration-none">
                                <i class="bi bi-box-arrow-up-right me-1"></i>Track
                            </a>
                        </td>

                        <td class="text-end pe-4">
                            <div class="d-flex justify-content-end gap-1">
                                <a :href="viewUrl + '&id=' + car.id"
                                   class="btn btn-sm btn-outline-info border-0 rounded-pill"
                                   title="View">
                                    <i class="bi bi-eye"></i>
                                </a>
                                <button @click="openModal(car)"
                                        class="btn btn-sm btn-outline-primary border-0 rounded-pill"
                                        title="Edit">
                                    <i class="bi bi-pencil-square"></i>
                                </button>
                                <button @click="askDelete(car.id)"
                                        class="btn btn-sm btn-outline-danger border-0 rounded-pill"
                                        title="Delete">
                                    <i class="bi bi-trash3"></i>
                                </button>
                            </div>
                        </td>

                    </tr>
                </tbody>
            </table>
        </div>

        <!-- Pagination -->
        <div class="card-footer bg-white border-top py-3
                    d-flex justify-content-between align-items-center flex-wrap gap-2"
             v-if="totalCount > 0">

            <div class="d-flex align-items-center gap-3 ps-2">
                <div class="small text-muted">
                    Showing <strong>{{ startIndex }}</strong>–<strong>{{ endIndex }}</strong>
                    of <strong>{{ totalCount }}</strong> vehicles
                </div>
                <div class="d-flex align-items-center gap-2">
                    <label class="small text-muted mb-0">Show:</label>
                    <select v-model.number="pageSize"
                            class="form-select form-select-sm w-auto border-0 shadow-sm rounded-pill"
                            style="min-width:70px;">
                        <option :value="10">10</option>
                        <option :value="15">15</option>
                        <option :value="25">25</option>
                        <option :value="50">50</option>
                        <option :value="100">100</option>
                    </select>
                </div>
            </div>

            <nav v-if="totalPages > 1">
                <ul class="pagination pagination-sm mb-0 gap-1">
                    <li class="page-item" :class="{ disabled: currentPage === 1 }">
                        <button class="page-link rounded-pill border-0 px-3" @click="goToPage(currentPage - 1)">
                            <i class="bi bi-chevron-left"></i>
                        </button>
                    </li>
                    <template v-for="page in visiblePages" :key="page">
                        <li v-if="page !== '...'"
                            class="page-item"
                            :class="{ active: currentPage === page }">
                            <button class="page-link rounded-pill border-0 px-3"
                                    @click="goToPage(page)">{{ page }}</button>
                        </li>
                        <li v-else class="page-item disabled">
                            <span class="page-link border-0 bg-transparent text-muted">…</span>
                        </li>
                    </template>
                    <li class="page-item" :class="{ disabled: currentPage === totalPages }">
                        <button class="page-link rounded-pill border-0 px-3" @click="goToPage(currentPage + 1)">
                            <i class="bi bi-chevron-right"></i>
                        </button>
                    </li>
                </ul>
            </nav>

        </div>
    </div>

    <!-- Modal Partial -->
    <?= $this->render('_modal', [
        'clients'      => $clients,
        'auctions'     => $auctions,
        'warehouses'   => $warehouses,
        'destinations' => $destinations,
    ]) ?>

    <!-- Delete Confirm Modal -->
    <div class="modal fade" id="deleteConfirmModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered modal-sm">
            <div class="modal-content border-0 shadow-lg rounded-4">
                <div class="modal-body text-center p-4">
                    <i class="bi bi-exclamation-triangle-fill text-danger d-block mb-3"
                       style="font-size:2.5rem;"></i>
                    <h6 class="fw-bold mb-1">Delete Vehicle?</h6>
                    <p class="text-muted small mb-4">
                        This will permanently delete the car and all its photos.
                        This cannot be undone.
                    </p>
                    <div class="d-flex gap-2 justify-content-center">
                        <button type="button"
                                class="btn btn-light rounded-pill px-4"
                                data-bs-dismiss="modal">Cancel</button>
                        <button type="button"
                                class="btn btn-danger rounded-pill px-4 fw-bold"
                                @click="confirmDelete"
                                :disabled="loading">
                            <span v-if="loading"
                                  class="spinner-border spinner-border-sm me-1"></span>
                            <i v-else class="bi bi-trash me-1"></i> Delete
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

</div><!-- end #carApp -->

<style>
[v-cloak]  { display: none !important; }
.table th  {
    font-size: 0.75rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.5px;
    padding-top: 1rem; padding-bottom: 1rem;
}
.table-hover tbody tr:hover { background-color: #f8f9fa !important; }
.object-fit-cover { object-fit: cover; }
.rounded-4        { border-radius: 1rem !important; }
.page-item.active .page-link {
    background-color: #0d6efd !important;
    color: #fff !important;
    font-weight: 600;
}
.page-link        { color: #555; transition: all 0.2s; }
.page-link:hover  { background-color: #e9ecef; color: #0d6efd; }
.drag-over        { border: 2px dashed #0d6efd !important; background-color: #f0f5ff !important; }
</style>

<?php
// ====================================================
// PART 2: Vue JS Application
// ====================================================
$this->registerJs(<<<'JS'

(function () {
    var createApp = Vue.createApp;

    if (!window.CarAppData) {
        console.error('[CarApp] window.CarAppData is not defined.');
        return;
    }

    var _data = window.CarAppData;

    // ✅ Zero-pad helper — avoids padStart compatibility issues
    function pad2(n) {
        return (n < 10 ? '0' : '') + n;
    }

    // ✅ Format Date object to YYYY-MM-DD
    function toYmd(d) {
        return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate());
    }

    // ✅ safeJsonParse — strips PHP warnings/notices before parsing
    function safeJsonParse(rawText) {
        var jsonStart = rawText.search(/[\{\[]/);
        if (jsonStart === -1) {
            throw new Error('No JSON found in response');
        }
        return JSON.parse(rawText.substring(jsonStart));
    }

    createApp({

        // ==================================================
        //  DATA
        // ==================================================
        data: function() {
            return {
                cars:         _data.cars         || [],
                totalCount:   _data.totalCount   || 0,
                statusCounts: _data.statusCounts || {},
                clients:      _data.clients       || [],
                auctions:     _data.auctions      || [],
                warehouses:   _data.warehouses    || [],
                destinations: _data.destinations  || [],

                saveUrl:       _data.saveUrl       || '',
                deleteUrl:     _data.deleteUrl     || '',
                viewUrl:       _data.viewUrl       || '',
                uploadBaseUrl: _data.uploadBaseUrl || '',
                defaultThumb:  _data.defaultThumb  || '',
                csrfToken:     _data.csrfToken     || '',
                csrfParam:     _data.csrfParam     || '_csrf',

                searchQuery: '',
                currentPage: 1,
                pageSize:    15,

                isEditing: false,
                loading:   false,

                formData: {
                    id: null, vin: '', lot: '', title: '', info: '',
                    liner: '', year: '', price: '', status: 'at_auction',
                    auction_id: '', warehouse_id: '', destination_id: '',
                    client_id: '', purchase_date: '', received_date: '',
                    eta_date: '', shipping_line: '', container: '', note: '',
                },

                formErrors: {
                    year:           false,
                    lot:            false,
                    title:          false,
                    info:           false,
                    liner:          false,
                    price:          false,
                    status:         false,
                    auction_id:     false,
                    warehouse_id:   false,
                    destination_id: false,
                    client_id:      false,
                    shipping_line:  false,
                    container:      false,
                    note:           false,
                },

                existingImages:  [],
                newFiles:        { auction: [], warehouse: [], loading: [] },
                newPreviews:     { auction: [], warehouse: [], loading: [] },
                deletedImageIds: [],

                deleteTargetId:      null,
                modalInstance:       null,
                deleteModalInstance: null,
                clientChoices:       null,
                flatpickrInstances:  {},

                liners: [
                    'CMA CGM','ONE-LINE','EVERGREEN','MAERSK',
                    'COSCO','HYUNDAI','ZIM','OOCL','MSC'
                ],

                photoStages: [
                    { id: 'auction',   label: 'Auction',   icon: 'bi-hammer' },
                    { id: 'warehouse', label: 'Warehouse', icon: 'bi-house'  },
                    { id: 'loading',   label: 'Loading',   icon: 'bi-truck'  },
                ],
                searchTimer: null,
            };
        },


        // ==================================================
        //  COMPUTED
        // ==================================================
        computed: {
            totalPages: function() {
                return Math.ceil(this.totalCount / this.pageSize) || 1;
            },

            startIndex: function() {
                return this.totalCount === 0
                    ? 0
                    : (this.currentPage - 1) * this.pageSize + 1;
            },

            endIndex: function() {
                return Math.min(
                    this.currentPage * this.pageSize,
                    this.totalCount
                );
            },

            statusStats: function() {
                var self = this;
                var list = [
                    { status: 'at_auction', label: 'At Auction', badge: 'bg-warning-subtle text-warning'  },
                    { status: 'at_yard',    label: 'At Yard',    badge: 'bg-info-subtle text-info'        },
                    { status: 'arrived',    label: 'Arrived',    badge: 'bg-success-subtle text-success'  },
                    { status: 'paid',       label: 'Paid',       badge: 'bg-primary-subtle text-primary'  },
                    { status: 'unpaid',     label: 'Unpaid',     badge: 'bg-danger-subtle text-danger'    },
                ];
                return list.map(function(s) {
                    return Object.assign({}, s, {
                        count: self.statusCounts[s.status] || 0,
                    });
                });
            },

            visiblePages: function() {
                var total   = this.totalPages;
                var current = this.currentPage;
                var pages   = [];

                if (total <= 7) {
                    for (var i = 1; i <= total; i++) pages.push(i);
                    return pages;
                }

                pages.push(1);
                if (current > 4) pages.push('...');

                var start = Math.max(2, current - 2);
                var end   = Math.min(total - 1, current + 2);
                for (var j = start; j <= end; j++) pages.push(j);

                if (current < total - 3) pages.push('...');
                pages.push(total);

                return pages;
            },

            hasFormErrors: function() {
                var errors = this.formErrors;
                return Object.keys(errors).some(function(k) {
                    return errors[k] === true;
                });
            },

        },


        // ==================================================
        //  WATCH
        // ==================================================
        watch: {
            pageSize: function() {
                this.currentPage = 1;
                this.fetchPage(1);
            },
        },


        // ==================================================
        //  LIFECYCLE
        // ==================================================
        mounted: function() {
            var self = this;

            self.modalInstance =
                new bootstrap.Modal(document.getElementById('carModal'));
            self.deleteModalInstance =
                new bootstrap.Modal(document.getElementById('deleteConfirmModal'));

            document.getElementById('carModal').addEventListener(
                'shown.bs.modal',
                function() {
                    self.initChoices();
                    self.initFlatpickr();
                }
            );

            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(mutation) {
                    mutation.addedNodes.forEach(function(node) {
                        if (node.nodeType !== 1) return;

                        var childInputs = node.querySelectorAll
                            ? Array.prototype.slice.call(
                                node.querySelectorAll('input, select, textarea')
                            )
                            : [];

                        var allInputs = (node.tagName &&
                            ['INPUT','SELECT','TEXTAREA'].indexOf(node.tagName) !== -1)
                            ? [node].concat(childInputs)
                            : childInputs;

                        allInputs.forEach(function(inp, idx) {
                            if (!inp.id && !inp.name) {
                                var unique = Date.now() + '_' + idx;
                                inp.id   = 'auto_field_' + unique;
                                inp.name = 'auto_field_' + unique;
                                if (inp.type === 'text' || inp.type === 'search') {
                                    inp.autocomplete = 'off';
                                }
                            }
                        });
                    });
                });
            });

            var modalEl = document.getElementById('carModal');
            if (modalEl) {
                observer.observe(modalEl, {
                    childList: true,
                    subtree:   true,
                });
            }

            self._inputObserver = observer;
        },


        // ==================================================
        //  METHODS
        // ==================================================
        methods: {
            /* ─── Search ──────────────────────────────────── */
            onSearchInput: function() {
                var self = this;
                self.currentPage = 1;
                clearTimeout(self.searchTimer);
                self.searchTimer = setTimeout(function() {
                    self.fetchPage(1);
                }, 400);
            },

            /* ─── Fetch page from server ──────────────────── */
            fetchPage: function(page) {
                var self = this;
                self.loading = true;

                var url = self.saveUrl.replace('save-ajax', 'index')
                    + '&ajax=1&page=' + page
                    + '&pageSize=' + self.pageSize
                    + (self.searchQuery ? '&search=' + encodeURIComponent(self.searchQuery) : '');

                fetch(url, {
                    headers: { 'X-Requested-With': 'XMLHttpRequest' }
                })
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    if (data.success) {
                        self.cars       = data.cars;
                        self.totalCount = data.total;
                    }
                })
                .catch(function(err) {
                    console.error('[fetchPage] error:', err);
                })
                .finally(function() {
                    self.loading = false;
                });
            },
            /* ─── Validation ──────────────────────────────── */
            validateField: function(field) {
                var value = this.formData[field];
                var empty = (value === ''
                          || value === null
                          || value === undefined
                          || value === 0
                          || value === '0');

                if (field === 'price') {
                    this.formErrors[field] = (value === '' || value === null || value === undefined);
                } else {
                    this.formErrors[field] = empty;
                }
            },

            validateForm: function() {
                var self = this;
                var requiredFields = [
                    'year', 'lot', 'title', 'info', 'liner', 'price',
                    'status', 'auction_id', 'warehouse_id', 'destination_id',
                    'client_id', 'shipping_line', 'container', 'note',
                ];
                requiredFields.forEach(function(field) {
                    self.validateField(field);
                });
                var errors = self.formErrors;
                return !Object.keys(errors).some(function(k) {
                    return errors[k] === true;
                });
            },

            resetFormErrors: function() {
                var self = this;
                Object.keys(self.formErrors).forEach(function(key) {
                    self.formErrors[key] = false;
                });
            },

            /* ─── Choices.js ──────────────────────────────── */
            // ─── Replace ONLY the initChoices method in your index.php Vue JS ───
            // Find: initChoices: function() {  ...  },
            // Replace with this entire block:

            initChoices: function() {
                var self = this;
                var el   = document.getElementById('clientSelectEl');
                if (!el) { console.warn('[CarApp] #clientSelectEl not found.'); return; }
                if (typeof Choices === 'undefined') { console.warn('[CarApp] Choices.js not loaded.'); return; }

                if (self.clientChoices) {
                    self.clientChoices.destroy();
                    self.clientChoices = null;
                }

                var list = [{
                    value:       '',
                    label:       '-- Select Client --',
                    selected:    !self.formData.client_id,
                    placeholder: true,
                }];

                self.clients.forEach(function(c) {
                    // ✅ Include no + name + phone all in the label so Choices.js searches all 3
                    var label = '';
                    if (c.no)    label += '[' + c.no + '] ';
                    label += c.name || '';
                    if (c.phone) label += ' — ' + c.phone;

                    list.push({
                        value:      String(c.id),
                        label:      label,
                        selected:   String(c.id) === String(self.formData.client_id),
                        // customProperties lets us store raw values for the info display below
                        customProperties: {
                            no:    c.no    || '',
                            name:  c.name  || '',
                            phone: c.phone || '',
                        },
                    });
                });

                self.clientChoices = new Choices(el, {
                    searchEnabled:          true,
                    searchFields:           ['label'],   // searches the full label (no+name+phone)
                    searchFloor:            1,           // start searching from 1 character
                    itemSelectText:         '',
                    shouldSort:             false,
                    searchPlaceholderValue: 'Search by No, Name or Phone...',
                    noResultsText:          'No client found',
                    choices:                list,
                    callbackOnCreateTemplates: function(template) {
                        return {
                            // ✅ Custom item template — show no / name / phone in 3 lines
                            choice: function(classNames, data) {
                                if (!data.value) {
                                    // Placeholder option
                                    return template('<div class="' + classNames.item + ' ' + classNames.itemChoice + ' text-muted py-2 px-3" data-choice data-id="' + data.id + '" data-value="' + data.value + '">' + data.label + '</div>');
                                }
                                var props  = data.customProperties || {};
                                var no     = props.no    ? '<span class="badge bg-secondary-subtle text-secondary border rounded-pill me-2" style="font-size:0.7rem;">' + props.no + '</span>' : '';
                                var name   = '<strong>' + (props.name || '') + '</strong>';
                                var phone  = props.phone ? '<span class="text-muted ms-2" style="font-size:0.8rem;"><i class="bi bi-telephone me-1"></i>' + props.phone + '</span>' : '';

                                return template(
                                    '<div class="' + classNames.item + ' ' + classNames.itemChoice + ' py-2 px-3" data-choice data-id="' + data.id + '" data-value="' + data.value + '" data-select-text="">' +
                                        '<div class="d-flex align-items-center flex-wrap gap-1">' +
                                            no + name + phone +
                                        '</div>' +
                                    '</div>'
                                );
                            },
                            // ✅ Selected item — show compact no + name
                            item: function(classNames, data) {
                                var props = data.customProperties || {};
                                var no    = props.no ? '[' + props.no + '] ' : '';
                                return template(
                                    '<div class="' + classNames.item + '" data-item data-id="' + data.id + '" data-value="' + data.value + '">' +
                                        no + (props.name || data.label) +
                                    '</div>'
                                );
                            },
                        };
                    },
                });

                // Fix autocomplete warnings on injected inputs
                var wrapper = el.closest('.choices') || el.parentElement;
                if (wrapper) {
                    var injectedInputs = wrapper.querySelectorAll('input[type="text"], input[type="search"]');
                    injectedInputs.forEach(function(inp, idx) {
                        if (!inp.id)   inp.id   = 'choicesSearchInput_' + idx;
                        if (!inp.name) inp.name = 'choices_search_' + idx;
                        inp.autocomplete = 'off';
                    });
                    var hiddenInputs = wrapper.querySelectorAll('input[type="hidden"]');
                    hiddenInputs.forEach(function(inp, idx) {
                        if (!inp.id)   inp.id   = 'choicesHidden_' + idx;
                        if (!inp.name) inp.name = 'choices_hidden_' + idx;
                    });
                }

                el.addEventListener('change', function(e) {
                    self.formData.client_id = e.target.value;
                    if (e.target.value) {
                        self.formErrors.client_id = false;
                    }
                });
            },

            /* ─── Flatpickr ───────────────────────────────── */
            initFlatpickr: function() {
                var self = this;

                function patchFlatpickrInputs(calendarEl) {
                    if (!calendarEl) return;
                    calendarEl.querySelectorAll('input, select').forEach(function(inp, idx) {
                        if (!inp.id)   inp.id   = 'fp_auto_' + Date.now() + '_' + idx;
                        if (!inp.name) inp.name = 'fp_auto_' + Date.now() + '_' + idx;
                        inp.autocomplete = 'off';
                    });
                }

                var commonConfig = {
                    dateFormat: 'd-m-Y',
                    altInput:   true,
                    altFormat:  'd-m-Y',
                    allowInput: true,
                    onReady: function(selectedDates, dateStr, instance) {
                        patchFlatpickrInputs(instance.calendarContainer);
                    },
                    onOpen: function(selectedDates, dateStr, instance) {
                        patchFlatpickrInputs(instance.calendarContainer);
                    },
                };

                if (self._fpPurchase) { self._fpPurchase.destroy(); self._fpPurchase = null; }
                if (self._fpReceived) { self._fpReceived.destroy(); self._fpReceived = null; }
                if (self._fpEta)      { self._fpEta.destroy();      self._fpEta      = null; }

                var purchaseEl = document.getElementById('purchaseDateInput');
                var receivedEl = document.getElementById('receivedDateInput');
                var etaEl      = document.getElementById('etaDateInput');

                if (purchaseEl) {
                    self._fpPurchase = flatpickr(purchaseEl, Object.assign({}, commonConfig, {
                        defaultDate: self.formData.purchase_date || null,
                        onChange: function(dates) {
                            self.formData.purchase_date = dates[0] ? toYmd(dates[0]) : null;
                        },
                    }));
                }

                if (receivedEl) {
                    self._fpReceived = flatpickr(receivedEl, Object.assign({}, commonConfig, {
                        defaultDate: self.formData.received_date || null,
                        onChange: function(dates) {
                            self.formData.received_date = dates[0] ? toYmd(dates[0]) : null;
                        },
                    }));
                }

                if (etaEl) {
                    self._fpEta = flatpickr(etaEl, Object.assign({}, commonConfig, {
                        defaultDate: self.formData.eta_date || null,
                        onChange: function(dates) {
                            self.formData.eta_date = dates[0] ? toYmd(dates[0]) : null;
                        },
                    }));
                }
            },

            /* ─── Lookup helpers ──────────────────────────── */
            getClientName: function(id) {
                var c = this.clients.find(function(x) { return x.id == id; });
                return c ? c.name : '';
            },
            getClientNo: function(id) {
                var c = this.clients.find(function(x) { return x.id == id; });
                return c ? c.no : '';
            },
            getClientPhone: function(id) {
                var c = this.clients.find(function(x) { return x.id == id; });
                return c ? c.phone : '';
            },
            getAuctionName: function(id) {
                var a = this.auctions.find(function(x) { return x.id == id; });
                return a ? a.name : '';
            },
            getWarehouseName: function(id) {
                var w = this.warehouses.find(function(x) { return x.id == id; });
                return w ? w.name : '';
            },

            /* ─── Formatters ──────────────────────────────── */
            formatDate: function(d) {
                if (!d) return '';
                if (d.indexOf('/') !== -1) return d;
                var dt = new Date(d + 'T00:00:00');
                return isNaN(dt.getTime()) ? d : dt.toLocaleDateString('en-GB');
            },

            formatNumber: function(val) {
                return parseFloat(val || 0).toLocaleString('en-US', {
                    minimumFractionDigits: 2,
                    maximumFractionDigits: 2,
                });
            },

            formatStatus: function(s) {
                var m = {
                    at_auction: 'At Auction',
                    at_yard:    'At Yard',
                    arrived:    'Arrived',
                    paid:       'Paid',
                    unpaid:     'Unpaid',
                };
                return m[s] || s;
            },

            toMysqlDate: function(str) {
                if (!str) return '';
                if (str.indexOf('/') !== -1) {
                    var p = str.split('/');
                    return p[2] + '-' + p[1] + '-' + p[0];
                }
                return str;
            },

            getStatusBadge: function(s) {
                var m = {
                    at_auction: 'bg-warning-subtle text-warning border border-warning-subtle',
                    at_yard:    'bg-info-subtle text-info border border-info-subtle',
                    arrived:    'bg-success-subtle text-success border border-success-subtle',
                    paid:       'bg-primary-subtle text-primary border border-primary-subtle',
                    unpaid:     'bg-danger-subtle text-danger border border-danger-subtle',
                };
                return m[s] || 'bg-secondary-subtle text-secondary';
            },

            /* ─── Pagination ──────────────────────────────── */
            goToPage: function(page) {
                if (page === '...' || page < 1 || page > this.totalPages) return;
                this.currentPage = page;
                this.fetchPage(page);
            },
            shouldShowPage: function(page) {
                return page === 1
                    || page === this.totalPages
                    || Math.abs(page - this.currentPage) <= 1;
            },

            shouldShowEllipsis: function(page) {
                if (page === 2 && this.currentPage > 3) return true;
                if (page === this.totalPages - 1
                    && this.currentPage < this.totalPages - 2) return true;
                return false;
            },

            /* ─── Image fallback ──────────────────────────── */
            onTableImgError: function(e) { e.target.src = this.defaultThumb; },
            onImgError: function(e)      { e.target.src = this.defaultThumb; },

            /* ─── Image helpers ───────────────────────────── */
            getExistingImages: function(type) {
                return this.existingImages.filter(function(i) {
                    return i.type === type;
                });
            },

            getPhotoCount: function(type) {
                return this.existingImages.filter(function(i) {
                    return i.type === type;
                }).length + (this.newPreviews[type] || []).length;
            },

            /* ─── File handling ───────────────────────────── */
            triggerFileInput: function(type) {
                var el = this.$refs['fileInput_' + type];
                if (!el) return;
                var input = Array.isArray(el) ? el[0] : el;
                if (input) input.click();
            },

            handleFileSelect: function(event, type) {
                this.processFiles(
                    Array.prototype.slice.call(event.target.files),
                    type
                );
                event.target.value = '';
            },

            processFiles: function(files, type) {
                var allowed = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
                var maxSize = 5 * 1024 * 1024;
                var self    = this;

                files.forEach(function(file) {
                    if (allowed.indexOf(file.type) === -1) {
                        alert('Invalid file type: ' + file.name);
                        return;
                    }
                    if (file.size > maxSize) {
                        alert('File too large (max 5MB): ' + file.name);
                        return;
                    }
                    self.newFiles[type].push(file);
                    var reader = new FileReader();
                    reader.onload = function(e) {
                        self.newPreviews[type].push(e.target.result);
                    };
                    reader.readAsDataURL(file);
                });
            },

            removeNewImage: function(type, index) {
                this.newFiles[type].splice(index, 1);
                this.newPreviews[type].splice(index, 1);
            },

            deleteExistingImage: function(imgId) {
                this.deletedImageIds.push(imgId);
                this.existingImages = this.existingImages.filter(function(i) {
                    return i.id !== imgId;
                });
            },

            onDragOver: function(event)  { event.currentTarget.classList.add('drag-over'); },
            onDragLeave: function(event) { event.currentTarget.classList.remove('drag-over'); },

            onDrop: function(event, type) {
                event.currentTarget.classList.remove('drag-over');
                this.processFiles(
                    Array.prototype.slice.call(event.dataTransfer.files),
                    type
                );
            },

            /* ─── Open Modal ──────────────────────────────── */
            openModal: function(car) {
                car = car || null;
                this.isEditing       = !!car;
                this.deletedImageIds = [];
                this.newFiles        = { auction: [], warehouse: [], loading: [] };
                this.newPreviews     = { auction: [], warehouse: [], loading: [] };

                this.resetFormErrors();

                var firstTab = document.getElementById('tab-basic-btn');
                if (firstTab) {
                    bootstrap.Tab.getOrCreateInstance(firstTab).show();
                }

                if (car) {
                    this.formData = JSON.parse(JSON.stringify(car));
                    this.existingImages = car.images
                        ? JSON.parse(JSON.stringify(car.images))
                        : [];
                } else {
                    this.formData = {
                        id: null, vin: '', lot: '', title: '', info: '',
                        liner: '', year: '', price: '', status: 'at_auction',
                        auction_id: '', warehouse_id: '', destination_id: '',
                        client_id: '', purchase_date: '', received_date: '',
                        eta_date: '', shipping_line: '', container: '', note: '',
                        thumbnail: '',
                    };
                    this.existingImages = [];
                }

                this.modalInstance.show();
            },

            /* ─── Save Car ────────────────────────────────── */
            saveCar: async function() {
                var self = this;

                if (!self.validateForm()) {
                    var tabBasicBtn = document.getElementById('tab-basic-btn');
                    if (tabBasicBtn) tabBasicBtn.click();

                    var modalBody = document.querySelector('#carModal .modal-body');
                    if (modalBody) modalBody.scrollTop = 0;

                    self.showToast('Please fill in all required fields marked with *', 'warning');
                    return;
                }

                self.loading = true;
                var parsed   = false;

                try {
                    var fd = new FormData();

                    fd.append(self.csrfParam, self.csrfToken);

                    if (self.formData.id) {
                        fd.append('id', self.formData.id);
                    }

                    var fields = [
                        'year', 'vin', 'lot', 'title', 'info', 'liner',
                        'purchase_date', 'received_date', 'eta_date',
                        'auction_id', 'warehouse_id', 'destination_id',
                        'container', 'shipping_line', 'price', 'status',
                        'client_id', 'note',
                    ];

                    var dateFields = ['purchase_date', 'received_date', 'eta_date'];

                    fields.forEach(function(field) {
                        var val = self.formData[field] != null ? self.formData[field] : '';
                        if (dateFields.indexOf(field) !== -1) {
                            val = self.toMysqlDate(val);
                        }
                        fd.append('Car[' + field + ']', val);
                    });

                    self.photoStages.forEach(function(stage) {
                        var files = self.newFiles[stage.id] || [];
                        files.forEach(function(file) {
                            fd.append('image_files[' + stage.id + '][]', file);
                        });
                    });

                    if (self.deletedImageIds && self.deletedImageIds.length > 0) {
                        self.deletedImageIds.forEach(function(id) {
                            fd.append('delete_image_ids[]', id);
                        });
                    }

                    var response = await fetch(self.saveUrl, {
                        method: 'POST',
                        body:   fd,
                    });

                    var rawText = await response.text();
                    var result;

                    try {
                        result = safeJsonParse(rawText);
                        parsed = true;
                    } catch (e) {
                        console.error('[CarApp] Non-JSON server response:', rawText.substring(0, 800));
                        alert('Server error. Please check the console for details.');
                    }

                    if (!parsed || !result) return;

                    if (result.success) {
                        if (self.isEditing) {
                            var idx = self.cars.findIndex(function(c) {
                                return c.id === result.car.id;
                            });
                            if (idx !== -1) {
                                self.cars.splice(idx, 1, result.car);
                            }
                        } else {
                            self.cars.unshift(result.car);
                        }

                        self.deletedImageIds = [];
                        self.modalInstance.hide();
                        self.showToast(
                            self.isEditing
                                ? 'Vehicle updated successfully!'
                                : 'Vehicle added successfully!',
                            'success'
                        );
                    } else {
                        console.error('[CarApp] Save errors:', result.errors);
                        var msgs = result.errors
                            ? Object.values(result.errors).flat().join('\n')
                            : (result.message || 'Save failed.');
                        alert('Save failed:\n' + msgs);
                    }

                } catch (err) {
                    console.error('[CarApp] saveCar exception:', err);
                    alert('An unexpected error occurred. Please try again.');
                } finally {
                    self.loading = false;
                }
            },

            /* ─── Delete ──────────────────────────────────── */
            askDelete: function(carId) {
                this.deleteTargetId = carId;
                this.deleteModalInstance.show();
            },

            confirmDelete: async function() {
                if (!this.deleteTargetId) {
                    console.error('[Delete] No deleteTargetId set!');
                    return;
                }

                var self = this;
                self.loading = true;

                try {
                    var fd = new FormData();
                    // ✅ FIX #1: Was broken — now correctly uses deleteTargetId
                    fd.append('id',           String(self.deleteTargetId));
                    fd.append(self.csrfParam, self.csrfToken);

                    var response = await fetch(self.deleteUrl, {
                        method:      'POST',
                        body:        fd,
                        credentials: 'same-origin',
                    });

                    var rawText = await response.text();

                    if (!response.ok) {
                        alert('Server HTTP error: ' + response.status + '\n\nSee console for details.');
                        return;
                    }

                    var result;
                    try {
                        var jsonStart = rawText.search(/[\{\[]/);
                        result = JSON.parse(
                            jsonStart === -1 ? rawText : rawText.substring(jsonStart)
                        );
                    } catch (e) {
                        console.error('[Delete] JSON parse failed:', e);
                        alert('Could not parse server response.\n\nRaw:\n' + rawText.substring(0, 500));
                        return;
                    }

                    if (result && result.success) {
                        var deletedId = self.deleteTargetId;

                        // ✅ FIX #2: No arrow function — use regular function
                        self.cars = self.cars.filter(function(c) {
                            return c.id != deletedId;
                        });

                        self.deleteTargetId = null;
                        self.deleteModalInstance.hide();

                        if (self.currentPage > self.totalPages) {
                            self.currentPage = self.totalPages;
                        }

                        self.showToast('Vehicle deleted successfully!', 'danger');

                    } else {
                        var msg = (result && result.message)
                            ? result.message
                            : 'Unknown server error.';
                        console.error('[Delete] Server returned failure:', msg);
                        alert('Delete failed: ' + msg);
                    }

                } catch (err) {
                    console.error('[Delete] Network/fetch exception:', err);
                    alert('Network error: ' + err.message);
                } finally {
                    self.loading = false;
                }
            },


            /* ─── Toast Notification ──────────────────────── */
            showToast: function(message, type) {
                type = type || 'success';

                document.querySelectorAll('.car-toast').forEach(function(t) {
                    t.remove();
                });

                var colorMap = {
                    success: 'bg-success',
                    danger:  'bg-danger',
                    warning: 'bg-warning text-dark',
                    info:    'bg-info text-dark',
                };
                var iconMap = {
                    success: 'bi-check-circle-fill',
                    danger:  'bi-trash-fill',
                    warning: 'bi-exclamation-triangle-fill',
                    info:    'bi-info-circle-fill',
                };

                var toast = document.createElement('div');
                toast.className =
                    'car-toast position-fixed bottom-0 end-0 m-4 p-3 '
                    + 'rounded-4 shadow-lg d-flex align-items-center gap-2 '
                    + (colorMap[type] || 'bg-success');

                if (type === 'warning' || type === 'info') {
                    toast.classList.add('text-dark');
                } else {
                    toast.classList.add('text-white');
                }

                toast.style.cssText =
                    'z-index:9999; min-width:300px; font-size:0.9rem; '
                    + 'opacity:1; transition:opacity 0.4s ease;';

                toast.innerHTML =
                    '<i class="bi ' + (iconMap[type] || 'bi-check-circle-fill') + ' fs-5"></i>'
                    + '<span>' + message + '</span>';

                document.body.appendChild(toast);

                setTimeout(function() {
                    toast.style.opacity = '0';
                    setTimeout(function() { toast.remove(); }, 400);
                }, 3000);
            },

        }, // end methods

    }).mount('#carApp');

})();

JS,
    \yii\web\View::POS_END
);
?>
