//
//  PasswordNavigationDataSource.swift
//  pass
//
//  Created by Sun, Mingshen on 1/16/21.
//  Copyright © 2021 Bob Sun. All rights reserved.
//

import passKit
import UIKit

struct Section {
    var title: String
    var entries: [PasswordTableEntry]
}

class PasswordNavigationDataSource: NSObject, UITableViewDataSource {
    var sections: [Section]
    var filteredSections: [Section]

    var isSearchActive = false
    let hideSectionHeaderThreshold = 6

    init(entries: [PasswordTableEntry] = []) {
        self.sections = buildSections(from: entries)
        self.filteredSections = sections
    }

    func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
        filteredSections[section].entries.count
    }

    func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
        showSectionTitles() ? filteredSections[section].title : nil
    }

    func tableView(_: UITableView, sectionForSectionIndexTitle _: String, at index: Int) -> Int {
        index
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) as! PasswordTableViewCell
        let entry = getPasswordTableEntry(at: indexPath)
        cell.configure(with: entry)
        return cell
    }

    func numberOfSections(in _: UITableView) -> Int {
        filteredSections.count
    }

    func sectionIndexTitles(for _: UITableView) -> [String]? {
        showSectionTitles() ? filteredSections.map(\.title) : nil
    }

    func showSectionTitles() -> Bool {
        !isSearchActive && filteredSections.count > hideSectionHeaderThreshold
    }

    func getPasswordTableEntry(at indexPath: IndexPath) -> PasswordTableEntry {
        filteredSections[indexPath.section].entries[indexPath.row]
    }

    func showTableEntries(matching text: String) {
        guard !text.isEmpty else {
            filteredSections = sections
            return
        }

        filteredSections = sections.map { section in
            let entries = section.entries.filter { $0.matches(text) }
            return Section(title: section.title, entries: entries)
        }
        .filter { !$0.entries.isEmpty }
    }

    func showUnsyncedTableEntries() {
        filteredSections = sections.map { section in
            let entries = section.entries.filter { !$0.isSynced }
            return Section(title: section.title, entries: entries)
        }
        .filter { !$0.entries.isEmpty }
    }
}

private func buildSections(from entries: [PasswordTableEntry]) -> [Section] {
    let collation = UILocalizedIndexedCollation.current()
    let sectionTitles = collation.sectionIndexTitles
    var sections = [Section]()

    // initialize all sections
    for titleNumber in 0 ..< sectionTitles.count {
        sections.append(Section(title: sectionTitles[titleNumber], entries: [PasswordTableEntry]()))
    }

    // put entries into sections
    for entry in entries {
        let sectionNumber = collation.section(for: entry, collationStringSelector: #selector(getter: PasswordTableEntry.title))
        sections[sectionNumber].entries.append(entry)
    }

    // sort each list and set sectionTitles
    for titleNumber in 0 ..< sectionTitles.count {
        let entriesToSort = sections[titleNumber].entries
        let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
        sections[titleNumber].entries = sortedEntries as! [PasswordTableEntry]
    }

    // only keep non-empty sections
    return sections.filter { !$0.entries.isEmpty }
}
