import { ListViewBase, separatorColorProperty, itemTemplatesProperty, iosEstimatedRowHeightProperty, stickyHeaderProperty, stickyHeaderTemplateProperty, stickyHeaderHeightProperty, sectionedProperty, showSearchProperty, searchAutoHideProperty } from './list-view-common';
import { View } from '../core/view';
import { Length } from '../styling/length-shared';
import { Observable } from '../../data/observable';
import { Color } from '../../color';
import { layout } from '../../utils';
import { SDK_VERSION } from '../../utils/constants';
import { StackLayout } from '../layouts/stack-layout';
import { ProxyViewContainer } from '../proxy-view-container';
import { profile } from '../../profiling';
import { Trace } from '../../trace';
import { Builder } from '../builder';
import { Label } from '../label';
import { isFunction } from '../../utils/types';
export * from './list-view-common';
const ITEMLOADING = ListViewBase.itemLoadingEvent;
const LOADMOREITEMS = ListViewBase.loadMoreItemsEvent;
const ITEMTAP = ListViewBase.itemTapEvent;
const DEFAULT_HEIGHT = 44;
const infinity = layout.makeMeasureSpec(0, layout.UNSPECIFIED);
var ListViewCell = (function (_super) {
    __extends(ListViewCell, _super);
    function ListViewCell() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    ListViewCell.initWithEmptyBackground = function () {
        var cell = ListViewCell.new();
        cell.backgroundColor = UIColor.clearColor;
        return cell;
    };
    ListViewCell.prototype.initWithStyleReuseIdentifier = function (style, reuseIdentifier) {
        var cell = _super.prototype.initWithStyleReuseIdentifier.call(this, style, reuseIdentifier);
        cell.backgroundColor = UIColor.clearColor;
        return cell;
    };
    ListViewCell.prototype.willMoveToSuperview = function (newSuperview) {
        var parent = (this.view ? this.view.parent : null);
        if (parent && !newSuperview) {
            parent._removeContainer(this);
        }
    };
    Object.defineProperty(ListViewCell.prototype, "view", {
        get: function () {
            return this.owner ? this.owner.deref() : null;
        },
        enumerable: true,
        configurable: true
    });
    return ListViewCell;
}(UITableViewCell));
var ListViewHeaderCell = (function (_super) {
    __extends(ListViewHeaderCell, _super);
    function ListViewHeaderCell() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    ListViewHeaderCell.initWithEmptyBackground = function () {
        var cell = ListViewHeaderCell.new();
        cell.backgroundColor = UIColor.clearColor;
        return cell;
    };
    ListViewHeaderCell.prototype.initWithReuseIdentifier = function (reuseIdentifier) {
        var cell = _super.prototype.initWithReuseIdentifier.call(this, reuseIdentifier);
        cell.backgroundColor = UIColor.clearColor;
        return cell;
    };
    ListViewHeaderCell.prototype.willMoveToSuperview = function (newSuperview) {
        var parent = (this.view ? this.view.parent : null);
        if (parent && !newSuperview) {
            parent._removeHeaderContainer(this);
        }
    };
    Object.defineProperty(ListViewHeaderCell.prototype, "view", {
        get: function () {
            return this.owner ? this.owner.deref() : null;
        },
        enumerable: true,
        configurable: true
    });
    return ListViewHeaderCell;
}(UITableViewHeaderFooterView));
function notifyForItemAtIndex(listView, cell, view, eventName, indexPath) {
    const args = {
        eventName: eventName,
        object: listView,
        index: indexPath.row,
        section: indexPath.section,
        view: view,
        ios: cell,
        android: undefined,
    };
    listView.notify(args);
    return args;
}
var DataSource = (function (_super) {
    __extends(DataSource, _super);
    function DataSource() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    DataSource.initWithOwner = function (owner) {
        var dataSource = DataSource.new();
        dataSource._owner = owner;
        return dataSource;
    };
    DataSource.prototype.numberOfSectionsInTableView = function (tableView) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner) {
            return 1;
        }
        var sections = owner._getSectionCount();
        if (Trace.isEnabled()) {
            Trace.write("ListView: numberOfSections = ".concat(sections, " (sectioned: ").concat(owner.sectioned, ")"), Trace.categories.Debug);
        }
        return sections;
    };
    DataSource.prototype.tableViewNumberOfRowsInSection = function (tableView, section) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner) {
            return 0;
        }
        var sectionItems = owner._getItemsInSection(section);
        var rowCount = sectionItems ? sectionItems.length : 0;
        if (Trace.isEnabled()) {
            Trace.write("ListView: numberOfRows in section ".concat(section, " = ").concat(rowCount), Trace.categories.Debug);
        }
        return rowCount;
    };
    DataSource.prototype.tableViewCellForRowAtIndexPath = function (tableView, indexPath) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        var cell;
        if (owner) {
            var template = owner._getItemTemplate(indexPath.row);
            cell = (tableView.dequeueReusableCellWithIdentifier(template.key) || ListViewCell.initWithEmptyBackground());
            owner._prepareCell(cell, indexPath);
            var cellView = cell.view;
            if (cellView && cellView.isLayoutRequired) {
                var width = layout.getMeasureSpecSize(owner.widthMeasureSpec);
                var rowHeight = owner._effectiveRowHeight;
                var cellHeight = rowHeight > 0 ? rowHeight : owner.getHeight(indexPath.row);
                cellView.iosOverflowSafeAreaEnabled = false;
                View.layoutChild(owner, cellView, 0, 0, width, cellHeight);
            }
        }
        else {
            cell = ListViewCell.initWithEmptyBackground();
        }
        return cell;
    };
    DataSource.ObjCProtocols = [UITableViewDataSource];
    return DataSource;
}(NSObject));
var UITableViewDelegateImpl = (function (_super) {
    __extends(UITableViewDelegateImpl, _super);
    function UITableViewDelegateImpl() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    UITableViewDelegateImpl.initWithOwner = function (owner) {
        var delegate = UITableViewDelegateImpl.new();
        delegate._owner = owner;
        delegate._measureCellMap = new Map();
        return delegate;
    };
    UITableViewDelegateImpl.prototype.tableViewWillDisplayCellForRowAtIndexPath = function (tableView, cell, indexPath) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner && indexPath.row === owner.items.length - 1) {
            owner.notify({
                eventName: LOADMOREITEMS,
                object: owner,
            });
        }
    };
    UITableViewDelegateImpl.prototype.tableViewWillSelectRowAtIndexPath = function (tableView, indexPath) {
        var _a;
        var cell = tableView.cellForRowAtIndexPath(indexPath);
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner) {
            notifyForItemAtIndex(owner, cell, cell.view, ITEMTAP, indexPath);
        }
        return indexPath;
    };
    UITableViewDelegateImpl.prototype.tableViewDidSelectRowAtIndexPath = function (tableView, indexPath) {
        tableView.deselectRowAtIndexPathAnimated(indexPath, true);
        return indexPath;
    };
    UITableViewDelegateImpl.prototype.tableViewHeightForRowAtIndexPath = function (tableView, indexPath) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner) {
            return tableView.estimatedRowHeight;
        }
        var height = owner.getHeight(indexPath.row);
        if (height === undefined) {
            var template = owner._getItemTemplate(indexPath.row);
            var cell = this._measureCellMap.get(template.key);
            if (!cell) {
                cell = tableView.dequeueReusableCellWithIdentifier(template.key) || ListViewCell.initWithEmptyBackground();
                this._measureCellMap.set(template.key, cell);
            }
            height = owner._prepareCell(cell, indexPath);
        }
        return layout.toDeviceIndependentPixels(height);
    };
    UITableViewDelegateImpl.prototype.tableViewViewForHeaderInSection = function (tableView, section) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner || !owner.stickyHeader || !owner.stickyHeaderTemplate) {
            if (Trace.isEnabled()) {
                Trace.write("ListView: No sticky header (stickyHeader: ".concat(owner === null || owner === void 0 ? void 0 : owner.stickyHeader, ", hasTemplate: ").concat(!!(owner === null || owner === void 0 ? void 0 : owner.stickyHeaderTemplate), ")"), Trace.categories.Debug);
            }
            return null;
        }
        if (Trace.isEnabled()) {
            Trace.write("ListView: Creating sticky header", Trace.categories.Debug);
        }
        var headerReuseIdentifier = "stickyHeader";
        var headerCell = tableView.dequeueReusableHeaderFooterViewWithIdentifier(headerReuseIdentifier);
        if (!headerCell) {
            headerCell = ListViewHeaderCell.alloc().initWithReuseIdentifier(headerReuseIdentifier);
            headerCell.backgroundColor = UIColor.clearColor;
        }
        owner._prepareHeader(headerCell, section);
        return headerCell;
    };
    UITableViewDelegateImpl.prototype.tableViewHeightForHeaderInSection = function (tableView, section) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner || !owner.stickyHeader) {
            return 0;
        }
        var height;
        if (owner.stickyHeaderHeight === "auto") {
            height = 44;
        }
        else {
            height = layout.toDeviceIndependentPixels(Length.toDevicePixels(owner.stickyHeaderHeight, 44));
        }
        if (Trace.isEnabled()) {
            Trace.write("ListView: Sticky header height: ".concat(height), Trace.categories.Debug);
        }
        return height;
    };
    UITableViewDelegateImpl.ObjCProtocols = [UITableViewDelegate];
    return UITableViewDelegateImpl;
}(NSObject));
var UITableViewRowHeightDelegateImpl = (function (_super) {
    __extends(UITableViewRowHeightDelegateImpl, _super);
    function UITableViewRowHeightDelegateImpl() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    UITableViewRowHeightDelegateImpl.initWithOwner = function (owner) {
        var delegate = UITableViewRowHeightDelegateImpl.new();
        delegate._owner = owner;
        return delegate;
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewWillDisplayCellForRowAtIndexPath = function (tableView, cell, indexPath) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner && indexPath.row === owner.items.length - 1) {
            owner.notify({
                eventName: LOADMOREITEMS,
                object: owner,
            });
        }
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewWillSelectRowAtIndexPath = function (tableView, indexPath) {
        var _a;
        var cell = tableView.cellForRowAtIndexPath(indexPath);
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner) {
            notifyForItemAtIndex(owner, cell, cell.view, ITEMTAP, indexPath);
        }
        return indexPath;
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewDidSelectRowAtIndexPath = function (tableView, indexPath) {
        tableView.deselectRowAtIndexPathAnimated(indexPath, true);
        return indexPath;
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewHeightForRowAtIndexPath = function (tableView, indexPath) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner) {
            return tableView.estimatedRowHeight;
        }
        return layout.toDeviceIndependentPixels(owner._effectiveRowHeight);
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewViewForHeaderInSection = function (tableView, section) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner || !owner.stickyHeader || !owner.stickyHeaderTemplate) {
            if (Trace.isEnabled()) {
                Trace.write("ListView: No sticky header (stickyHeader: ".concat(owner === null || owner === void 0 ? void 0 : owner.stickyHeader, ", hasTemplate: ").concat(!!(owner === null || owner === void 0 ? void 0 : owner.stickyHeaderTemplate), ")"), Trace.categories.Debug);
            }
            return null;
        }
        if (Trace.isEnabled()) {
            Trace.write("ListView: Creating sticky header", Trace.categories.Debug);
        }
        var headerReuseIdentifier = "stickyHeader";
        var headerCell = tableView.dequeueReusableHeaderFooterViewWithIdentifier(headerReuseIdentifier);
        if (!headerCell) {
            headerCell = ListViewHeaderCell.alloc().initWithReuseIdentifier(headerReuseIdentifier);
            headerCell.backgroundColor = UIColor.clearColor;
        }
        owner._prepareHeader(headerCell, section);
        return headerCell;
    };
    UITableViewRowHeightDelegateImpl.prototype.tableViewHeightForHeaderInSection = function (tableView, section) {
        var _a;
        var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (!owner || !owner.stickyHeader) {
            return 0;
        }
        var height;
        if (owner.stickyHeaderHeight === "auto") {
            height = 44;
        }
        else {
            height = layout.toDeviceIndependentPixels(Length.toDevicePixels(owner.stickyHeaderHeight, 44));
        }
        if (Trace.isEnabled()) {
            Trace.write("ListView: Sticky header height: ".concat(height), Trace.categories.Debug);
        }
        return height;
    };
    UITableViewRowHeightDelegateImpl.ObjCProtocols = [UITableViewDelegate];
    return UITableViewRowHeightDelegateImpl;
}(NSObject));
var UISearchResultsUpdatingImpl = (function (_super) {
    __extends(UISearchResultsUpdatingImpl, _super);
    function UISearchResultsUpdatingImpl() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    UISearchResultsUpdatingImpl.initWithOwner = function (owner) {
        var handler = UISearchResultsUpdatingImpl.new();
        handler._owner = owner;
        return handler;
    };
    UISearchResultsUpdatingImpl.prototype.updateSearchResultsForSearchController = function (searchController) {
        var owner = this._owner ? this._owner.get() : null;
        if (!owner) {
            return;
        }
        var searchText = searchController.searchBar.text || "";
        owner._isSearchActive = searchController.active;
        var eventData = {
            eventName: ListViewBase.searchChangeEvent,
            object: owner,
            text: searchText,
            ios: searchController,
        };
        owner.notify(eventData);
    };
    UISearchResultsUpdatingImpl.ObjCProtocols = [UISearchResultsUpdating];
    return UISearchResultsUpdatingImpl;
}(NSObject));
export class ListView extends ListViewBase {
    constructor() {
        super();
        this._isSearchActive = false;
        this.widthMeasureSpec = 0;
        this._map = new Map();
        this._headerMap = new Map();
        this._heights = new Array();
    }
    createNativeView() {
        return UITableView.new();
    }
    initNativeView() {
        super.initNativeView();
        const nativeView = this.nativeViewProtected;
        nativeView.registerClassForCellReuseIdentifier(ListViewCell.class(), this._defaultTemplate.key);
        nativeView.registerClassForHeaderFooterViewReuseIdentifier(ListViewHeaderCell.class(), 'stickyHeader');
        nativeView.estimatedRowHeight = DEFAULT_HEIGHT;
        nativeView.rowHeight = UITableViewAutomaticDimension;
        nativeView.dataSource = this._dataSource = DataSource.initWithOwner(new WeakRef(this));
        this._delegate = UITableViewDelegateImpl.initWithOwner(new WeakRef(this));
        // Control section header top padding (iOS 15+)
        if (nativeView.respondsToSelector('setSectionHeaderTopPadding:')) {
            if (!this.stickyHeaderTopPadding) {
                nativeView.sectionHeaderTopPadding = 0;
            }
            // When stickyHeaderTopPadding is true, don't set the property to use iOS default
        }
        this._setNativeClipToBounds();
    }
    disposeNativeView() {
        this._cleanupSearchController();
        this._delegate = null;
        this._dataSource = null;
        super.disposeNativeView();
    }
    _setupSearchController() {
        if (!this.showSearch || this._searchController) {
            return; // Already setup or not needed
        }
        // 1. Create UISearchController with nil (show results in this table)
        this._searchController = UISearchController.alloc().initWithSearchResultsController(null);
        this._searchDelegate = UISearchResultsUpdatingImpl.initWithOwner(new WeakRef(this));
        // 2. Tell it who will update results
        this._searchController.searchResultsUpdater = this._searchDelegate;
        // 3. Critical: Don't dim or obscure the table, and prevent extra content
        this._searchController.obscuresBackgroundDuringPresentation = false;
        this._searchController.dimsBackgroundDuringPresentation = false;
        this._searchController.hidesNavigationBarDuringPresentation = false;
        // 4. Placeholder text and styling
        this._searchController.searchBar.placeholder = 'Search';
        this._searchController.searchBar.searchBarStyle = 2 /* UISearchBarStyle.Minimal */;
        // 5. CRITICAL: Proper presentation context setup
        const viewController = this._getViewController();
        if (viewController) {
            viewController.definesPresentationContext = true;
            viewController.providesPresentationContextTransitionStyle = true;
            // 6a. If we're in a UINavigationController (iOS 11+)...
            if (SDK_VERSION >= 11.0 && viewController.navigationItem) {
                viewController.navigationItem.searchController = this._searchController;
                // Set auto-hide behavior based on searchAutoHide property
                viewController.navigationItem.hidesSearchBarWhenScrolling = this.searchAutoHide;
                // Optional: Enable large titles for better auto-hide effect when searchAutoHide is true
                // if (this.searchAutoHide && viewController.navigationController && viewController.navigationController.navigationBar) {
                // 	// Only set large titles if not already configured
                // 	if (!viewController.navigationController.navigationBar.prefersLargeTitles) {
                // 		viewController.navigationController.navigationBar.prefersLargeTitles = true;
                // 	}
                // 	// Set large title display mode for this specific view controller
                // 	if (viewController.navigationItem.largeTitleDisplayMode === UINavigationItemLargeTitleDisplayMode.Automatic) {
                // 		viewController.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Always;
                // 	}
                // }
            }
            else {
                // 6b. Fallback: put it at the top of our table
                this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
            }
        }
        else {
            // Fallback: no view controller found, use table header
            this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
        }
        // 7. Ensure search bar is properly sized and prevent content inset issues
        this._searchController.searchBar.sizeToFit();
        // 8. Disable automatic content inset adjustment that can cause spacing issues
        if (this.nativeViewProtected.respondsToSelector('setContentInsetAdjustmentBehavior:')) {
            // iOS 11+ - prevent automatic content inset adjustments
            this.nativeViewProtected.contentInsetAdjustmentBehavior = 2 /* UIScrollViewContentInsetAdjustmentBehavior.Never */;
        }
        else {
            // iOS 10 and below - disable automatic content inset
            this.nativeViewProtected.automaticallyAdjustsScrollIndicatorInsets = false;
        }
        if (Trace.isEnabled()) {
            Trace.write(`ListView: UISearchController setup complete with searchAutoHide: ${this.searchAutoHide}`, Trace.categories.Debug);
        }
    }
    _cleanupSearchController() {
        if (!this._searchController) {
            return;
        }
        // Remove search controller from navigation item or table header
        const viewController = this._getViewController();
        if (viewController && viewController.navigationItem && viewController.navigationItem.searchController === this._searchController) {
            viewController.navigationItem.searchController = null;
        }
        else if (this.nativeViewProtected.tableHeaderView === this._searchController.searchBar) {
            this.nativeViewProtected.tableHeaderView = null;
        }
        // Reset content inset adjustment behavior
        if (this.nativeViewProtected.respondsToSelector('setContentInsetAdjustmentBehavior:')) {
            // iOS 11+ - restore automatic content inset adjustments
            this.nativeViewProtected.contentInsetAdjustmentBehavior = 0 /* UIScrollViewContentInsetAdjustmentBehavior.Automatic */;
        }
        else {
            // iOS 10 and below - restore automatic content inset
            this.nativeViewProtected.automaticallyAdjustsScrollIndicatorInsets = true;
        }
        // Cleanup references
        this._searchController.searchResultsUpdater = null;
        this._searchController = null;
        this._searchDelegate = null;
    }
    _getViewController() {
        // Helper to get the current view controller
        let parent = this.parent;
        while (parent) {
            if (parent.viewController) {
                return parent.viewController;
            }
            parent = parent.parent;
        }
        return null;
    }
    _setNativeClipToBounds() {
        // Always set clipsToBounds for list-view
        const view = this.nativeViewProtected;
        if (view) {
            view.clipsToBounds = true;
        }
    }
    onLoaded() {
        super.onLoaded();
        if (this._isDataDirty) {
            this.refresh();
        }
        this.nativeViewProtected.delegate = this._delegate;
        // Setup search controller if enabled
        if (this.showSearch) {
            this._setupSearchController();
        }
    }
    // @ts-ignore
    get ios() {
        return this.nativeViewProtected;
    }
    get _childrenCount() {
        return this._map.size + this._headerMap.size;
    }
    eachChildView(callback) {
        this._map.forEach((view, key) => {
            callback(view);
        });
        this._headerMap.forEach((view, key) => {
            callback(view);
        });
    }
    scrollToIndex(index) {
        this._scrollToIndex(index, false);
    }
    scrollToIndexAnimated(index) {
        this._scrollToIndex(index);
    }
    _scrollToIndex(index, animated = true) {
        if (!this.nativeViewProtected) {
            return;
        }
        const itemsLength = this.items ? this.items.length : 0;
        // mimic Android behavior that silently coerces index values within [0, itemsLength - 1] range
        if (itemsLength > 0) {
            if (index < 0) {
                index = 0;
            }
            else if (index >= itemsLength) {
                index = itemsLength - 1;
            }
            this.nativeViewProtected.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0), 1 /* UITableViewScrollPosition.Top */, animated);
        }
        else if (Trace.isEnabled()) {
            Trace.write(`Cannot scroll listview to index ${index} when listview items not set`, Trace.categories.Binding);
        }
    }
    refresh() {
        // clear bindingContext when it is not observable because otherwise bindings to items won't reevaluate
        this._map.forEach((view, nativeView, map) => {
            if (!(view.bindingContext instanceof Observable)) {
                view.bindingContext = null;
            }
        });
        this._headerMap.forEach((view, nativeView, map) => {
            if (!(view.bindingContext instanceof Observable)) {
                view.bindingContext = null;
            }
        });
        if (this.isLoaded) {
            this.nativeViewProtected.reloadData();
            this.requestLayout();
            this._isDataDirty = false;
        }
        else {
            this._isDataDirty = true;
        }
    }
    isItemAtIndexVisible(itemIndex) {
        const indexes = Array.from(this.nativeViewProtected.indexPathsForVisibleRows);
        return indexes.some((visIndex) => visIndex.row === itemIndex);
    }
    getHeight(index) {
        return this._heights[index];
    }
    setHeight(index, value) {
        this._heights[index] = value;
    }
    _onRowHeightPropertyChanged(oldValue, newValue) {
        const value = layout.toDeviceIndependentPixels(this._effectiveRowHeight);
        const nativeView = this.nativeViewProtected;
        if (value < 0) {
            nativeView.rowHeight = UITableViewAutomaticDimension;
            nativeView.estimatedRowHeight = DEFAULT_HEIGHT;
            this._delegate = UITableViewDelegateImpl.initWithOwner(new WeakRef(this));
        }
        else {
            nativeView.rowHeight = value;
            nativeView.estimatedRowHeight = value;
            this._delegate = UITableViewRowHeightDelegateImpl.initWithOwner(new WeakRef(this));
        }
        if (this.isLoaded) {
            nativeView.delegate = this._delegate;
        }
        super._onRowHeightPropertyChanged(oldValue, newValue);
    }
    requestLayout() {
        // When preparing cell or header don't call super - no need to invalidate our measure when cell/header desiredSize is changed.
        if (!this._preparingCell && !this._preparingHeader) {
            super.requestLayout();
        }
    }
    measure(widthMeasureSpec, heightMeasureSpec) {
        const changed = this._currentWidthMeasureSpec !== widthMeasureSpec || this._currentHeightMeasureSpec !== heightMeasureSpec;
        this.widthMeasureSpec = widthMeasureSpec;
        super.measure(widthMeasureSpec, heightMeasureSpec);
        // Reload native view cells only in the case of size change
        if (changed) {
            this.nativeViewProtected.reloadData();
        }
    }
    onMeasure(widthMeasureSpec, heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        this._map.forEach((childView, listViewCell) => {
            View.measureChild(this, childView, childView._currentWidthMeasureSpec, childView._currentHeightMeasureSpec);
        });
        this._headerMap.forEach((childView, listViewHeaderCell) => {
            View.measureChild(this, childView, childView._currentWidthMeasureSpec, childView._currentHeightMeasureSpec);
        });
    }
    onLayout(left, top, right, bottom) {
        super.onLayout(left, top, right, bottom);
        this._map.forEach((childView, listViewCell) => {
            const rowHeight = this._effectiveRowHeight;
            const cellHeight = rowHeight > 0 ? rowHeight : this.getHeight(childView._listViewItemIndex);
            if (cellHeight) {
                const width = layout.getMeasureSpecSize(this.widthMeasureSpec);
                childView.iosOverflowSafeAreaEnabled = false;
                View.layoutChild(this, childView, 0, 0, width, cellHeight);
            }
        });
        this._headerMap.forEach((childView, listViewHeaderCell) => {
            const headerHeight = this.stickyHeaderHeight === 'auto' ? 44 : Length.toDevicePixels(this.stickyHeaderHeight, 44);
            const width = layout.getMeasureSpecSize(this.widthMeasureSpec);
            childView.iosOverflowSafeAreaEnabled = false;
            View.layoutChild(this, childView, 0, 0, width, headerHeight);
        });
    }
    _layoutCell(cellView, indexPath) {
        if (cellView) {
            const rowHeight = this._effectiveRowHeight;
            const heightMeasureSpec = rowHeight >= 0 ? layout.makeMeasureSpec(rowHeight, layout.EXACTLY) : infinity;
            const measuredSize = View.measureChild(this, cellView, this.widthMeasureSpec, heightMeasureSpec);
            const height = measuredSize.measuredHeight;
            this.setHeight(indexPath.row, height);
            return height;
        }
        return this.nativeViewProtected.estimatedRowHeight;
    }
    _prepareCell(cell, indexPath) {
        let cellHeight;
        try {
            this._preparingCell = true;
            let view = cell.view;
            if (!view) {
                if (this.sectioned) {
                    // For sectioned data, we need to calculate the absolute index for template selection
                    let absoluteIndex = 0;
                    for (let i = 0; i < indexPath.section; i++) {
                        absoluteIndex += this._getItemsInSection(i).length;
                    }
                    absoluteIndex += indexPath.row;
                    view = this._getItemTemplate(absoluteIndex).createView();
                }
                else {
                    view = this._getItemTemplate(indexPath.row).createView();
                }
            }
            const args = notifyForItemAtIndex(this, cell, view, ITEMLOADING, indexPath);
            view = args.view || this._getDefaultItemContent(this.sectioned ? indexPath.row : indexPath.row);
            // Proxy containers should not get treated as layouts.
            // Wrap them in a real layout as well.
            if (view instanceof ProxyViewContainer) {
                const sp = new StackLayout();
                sp.addChild(view);
                view = sp;
            }
            // If cell is reused it have old content - remove it first.
            if (!cell.view) {
                cell.owner = new WeakRef(view);
            }
            else if (cell.view !== view) {
                // Remove view from super view now as nativeViewProtected will be null afterwards
                cell.view.nativeViewProtected?.removeFromSuperview();
                this._removeContainer(cell);
                cell.owner = new WeakRef(view);
            }
            if (this.sectioned) {
                this._prepareItemInSection(view, indexPath.section, indexPath.row);
                view._listViewItemIndex = indexPath.row; // Keep row index for compatibility
                view._listViewSectionIndex = indexPath.section;
            }
            else {
                this._prepareItem(view, indexPath.row);
                view._listViewItemIndex = indexPath.row;
            }
            this._map.set(cell, view);
            // We expect that views returned from itemLoading are new (e.g. not reused).
            if (view && !view.parent) {
                this._addView(view);
                cell.contentView.addSubview(view.nativeViewProtected);
            }
            cellHeight = this._layoutCell(view, indexPath);
        }
        finally {
            this._preparingCell = false;
        }
        return cellHeight;
    }
    _removeContainer(cell) {
        const view = cell.view;
        // This is to clear the StackLayout that is used to wrap ProxyViewContainer instances.
        if (!(view.parent instanceof ListView)) {
            this._removeView(view.parent);
        }
        // No need to request layout when we are removing cells.
        const preparing = this._preparingCell;
        this._preparingCell = true;
        view.parent._removeView(view);
        view._listViewItemIndex = undefined;
        this._preparingCell = preparing;
        this._map.delete(cell);
    }
    _prepareHeader(headerCell, section) {
        let headerHeight;
        try {
            this._preparingHeader = true;
            let view = headerCell.view;
            if (!view) {
                view = this._getHeaderTemplate();
                if (!view) {
                    if (Trace.isEnabled()) {
                        Trace.write(`ListView: Failed to create header view for section ${section}`, Trace.categories.Debug);
                    }
                    // Create a fallback view
                    const lbl = new Label();
                    lbl.text = `Section ${section}`;
                    view = lbl;
                }
            }
            // Handle header cell reuse
            if (!headerCell.view) {
                headerCell.owner = new WeakRef(view);
            }
            else if (headerCell.view !== view) {
                // Remove old view and set new one
                headerCell.view.nativeViewProtected?.removeFromSuperview();
                this._removeHeaderContainer(headerCell);
                headerCell.owner = new WeakRef(view);
            }
            // Clear existing binding context and set new one
            if (view.bindingContext) {
                view.bindingContext = null;
            }
            if (this.sectioned) {
                const sectionData = this._getSectionData(section);
                if (sectionData) {
                    view.bindingContext = sectionData;
                }
                else {
                    // Fallback if section data is missing
                    view.bindingContext = { title: `Section ${section}`, section: section };
                }
            }
            else {
                view.bindingContext = this.bindingContext;
            }
            // Force immediate binding context evaluation
            if (view && typeof view._onBindingContextChanged === 'function') {
                view._onBindingContextChanged(null, view.bindingContext);
                // Also trigger for child views
                // @ts-ignore
                if (view._childrenCount) {
                    view.eachChildView((child) => {
                        if (typeof child._onBindingContextChanged === 'function') {
                            child._onBindingContextChanged(null, view.bindingContext);
                        }
                        return true;
                    });
                }
            }
            this._headerMap.set(headerCell, view);
            // Add new header view to the cell
            if (view && !view.parent) {
                this._addView(view);
                headerCell.contentView.addSubview(view.nativeViewProtected);
            }
            // Request layout and measure/layout the header
            if (view && view.bindingContext) {
                view.requestLayout();
            }
            headerHeight = this._layoutHeader(view);
        }
        finally {
            this._preparingHeader = false;
        }
        return headerHeight;
    }
    _layoutHeader(headerView) {
        if (headerView) {
            const headerHeight = this.stickyHeaderHeight === 'auto' ? 44 : Length.toDevicePixels(this.stickyHeaderHeight, 44);
            const heightMeasureSpec = layout.makeMeasureSpec(headerHeight, layout.EXACTLY);
            const measuredSize = View.measureChild(this, headerView, this.widthMeasureSpec, heightMeasureSpec);
            // Layout the header with the measured size
            View.layoutChild(this, headerView, 0, 0, measuredSize.measuredWidth, measuredSize.measuredHeight);
            return measuredSize.measuredHeight;
        }
        return 44;
    }
    _getHeaderTemplate() {
        if (this.stickyHeaderTemplate) {
            if (__UI_USE_EXTERNAL_RENDERER__) {
                if (isFunction(this.stickyHeaderTemplate)) {
                    return this.stickyHeaderTemplate();
                }
            }
            else {
                if (typeof this.stickyHeaderTemplate === 'string') {
                    try {
                        const parsed = Builder.parse(this.stickyHeaderTemplate, this);
                        if (!parsed) {
                            // Create a simple fallback
                            const fallbackLabel = new Label();
                            fallbackLabel.text = 'Parse Failed';
                            return fallbackLabel;
                        }
                        return parsed;
                    }
                    catch (error) {
                        if (Trace.isEnabled()) {
                            Trace.write(`ListView: Template parsing error: ${error}`, Trace.categories.Debug);
                        }
                        // Create a simple fallback
                        const errorLabel = new Label();
                        errorLabel.text = 'Template Error';
                        return errorLabel;
                    }
                }
                else {
                    const view = this.stickyHeaderTemplate();
                    if (Trace.isEnabled()) {
                        Trace.write(`ListView: Created header view from template function: ${!!view} (type: ${view?.constructor?.name})`, Trace.categories.Debug);
                    }
                    return view;
                }
            }
        }
        if (Trace.isEnabled()) {
            Trace.write(`ListView: No sticky header template, creating default`, Trace.categories.Debug);
        }
        // Return a default header if no template is provided
        const lbl = new Label();
        lbl.text = 'Default Header';
        return lbl;
    }
    _removeHeaderContainer(headerCell) {
        const view = headerCell.view;
        // This is to clear the StackLayout that is used to wrap ProxyViewContainer instances.
        if (!(view.parent instanceof ListView)) {
            this._removeView(view.parent);
        }
        // No need to request layout when we are removing headers.
        const preparing = this._preparingHeader;
        this._preparingHeader = true;
        view.parent._removeView(view);
        this._preparingHeader = preparing;
        this._headerMap.delete(headerCell);
    }
    [separatorColorProperty.getDefault]() {
        return this.nativeViewProtected.separatorColor;
    }
    [separatorColorProperty.setNative](value) {
        this.nativeViewProtected.separatorColor = value instanceof Color ? value.ios : value;
    }
    [itemTemplatesProperty.getDefault]() {
        return null;
    }
    [itemTemplatesProperty.setNative](value) {
        this._itemTemplatesInternal = new Array(this._defaultTemplate);
        if (value) {
            for (let i = 0, length = value.length; i < length; i++) {
                this.nativeViewProtected.registerClassForCellReuseIdentifier(ListViewCell.class(), value[i].key);
            }
            this._itemTemplatesInternal = this._itemTemplatesInternal.concat(value);
        }
        this.refresh();
    }
    [iosEstimatedRowHeightProperty.getDefault]() {
        return DEFAULT_HEIGHT;
    }
    [iosEstimatedRowHeightProperty.setNative](value) {
        const nativeView = this.nativeViewProtected;
        const estimatedHeight = layout.toDeviceIndependentPixels(Length.toDevicePixels(value, 0));
        nativeView.estimatedRowHeight = estimatedHeight < 0 ? DEFAULT_HEIGHT : estimatedHeight;
    }
    [stickyHeaderProperty.getDefault]() {
        return false;
    }
    [stickyHeaderProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: stickyHeader set to ${value}`, Trace.categories.Debug);
        }
        // Immediately refresh to apply changes
        if (this.isLoaded) {
            this.refresh();
        }
    }
    [stickyHeaderTemplateProperty.getDefault]() {
        return null;
    }
    [stickyHeaderTemplateProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: stickyHeaderTemplate set: ${typeof value} ${value ? '(has value)' : '(null)'}`, Trace.categories.Debug);
        }
        // Clear any cached template
        this._headerTemplateCache = null;
        // Immediately refresh to apply changes
        if (this.isLoaded) {
            this.refresh();
        }
    }
    [stickyHeaderHeightProperty.getDefault]() {
        return 'auto';
    }
    [stickyHeaderHeightProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: stickyHeaderHeight set to ${value}`, Trace.categories.Debug);
        }
        // Immediately refresh to apply changes
        if (this.isLoaded) {
            this.refresh();
        }
    }
    [sectionedProperty.getDefault]() {
        return false;
    }
    [sectionedProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: sectioned set to ${value}`, Trace.categories.Debug);
        }
        // Immediately refresh to apply changes
        if (this.isLoaded) {
            this.refresh();
        }
    }
    [showSearchProperty.getDefault]() {
        return false;
    }
    [showSearchProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: showSearch set to ${value}`, Trace.categories.Debug);
        }
        if (value) {
            this._setupSearchController();
        }
        else {
            this._cleanupSearchController();
        }
    }
    [searchAutoHideProperty.getDefault]() {
        return false;
    }
    [searchAutoHideProperty.setNative](value) {
        if (Trace.isEnabled()) {
            Trace.write(`ListView: searchAutoHide set to ${value}`, Trace.categories.Debug);
        }
        // If search is already enabled, update the existing search controller
        if (this.showSearch && this._searchController) {
            const viewController = this._getViewController();
            if (viewController && viewController.navigationItem && SDK_VERSION >= 11.0) {
                viewController.navigationItem.hidesSearchBarWhenScrolling = value;
                // Enable large titles for better auto-hide effect when searchAutoHide is true
                // if (value && viewController.navigationController && viewController.navigationController.navigationBar) {
                // 	if (!viewController.navigationController.navigationBar.prefersLargeTitles) {
                // 		viewController.navigationController.navigationBar.prefersLargeTitles = true;
                // 	}
                // 	if (viewController.navigationItem.largeTitleDisplayMode === UINavigationItemLargeTitleDisplayMode.Automatic) {
                // 		viewController.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Always;
                // 	}
                // }
            }
        }
        // If search is not enabled yet, the property will be used when _setupSearchController is called
    }
}
__decorate([
    profile,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], ListView.prototype, "onLoaded", null);
//# sourceMappingURL=index.ios.js.map