import UIKit

private final class CommitHeaderView: UIView {
    private let stack = UIStackView()
    private let titleLabel = UILabel()
    private var descriptionView: UIView?
    private let metadataStack = UIStackView()
    private let bottomSeparator = separator()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .systemBackground
        directionalLayoutMargins = .init(top: 20, leading: 20, bottom: 20, trailing: 20)

        titleLabel.font = .preferredFont(forTextStyle: .title2)
        titleLabel.adjustsFontForContentSizeCategory = true
        titleLabel.numberOfLines = 0
        titleLabel.accessibilityTraits = .header

        metadataStack.axis = .vertical
        metadataStack.spacing = 10
        stack.axis = .vertical
        stack.spacing = 12
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.addArrangedSubview(titleLabel)
        stack.addArrangedSubview(metadataStack)
        addSubview(stack)
        bottomSeparator.translatesAutoresizingMaskIntoConstraints = false
        addSubview(bottomSeparator)
        NSLayoutConstraint.activate([
            stack.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
            stack.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
            stack.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
            stack.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
            bottomSeparator.leadingAnchor.constraint(equalTo: leadingAnchor),
            bottomSeparator.trailingAnchor.constraint(equalTo: trailingAnchor),
            bottomSeparator.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }

    func configure(_ page: CommitDetailsPage) {
        titleLabel.text = page.title
        descriptionView?.removeFromSuperview()
        if !page.description.isEmpty {
            let view = markdownView(page.description)
            stack.insertArrangedSubview(view, at: 1)
            descriptionView = view
        }
        metadataStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        for metadata in page.metadata {
            let label = UILabel()
            label.text = metadata.label.uppercased()
            label.font = .preferredFont(forTextStyle: .caption2)
            label.adjustsFontForContentSizeCategory = true
            label.textColor = .secondaryLabel

            let value = UILabel()
            value.text = metadata.value
            value.font = metadata.monospaced
                ? UIFontMetrics(forTextStyle: .subheadline).scaledFont(
                    for: .monospacedSystemFont(ofSize: 15, weight: .regular)
                )
                : .preferredFont(forTextStyle: .subheadline)
            value.adjustsFontForContentSizeCategory = true
            value.numberOfLines = 0
            value.lineBreakMode = metadata.monospaced ? .byCharWrapping : .byWordWrapping

            let row = UIStackView(arrangedSubviews: [label, value])
            row.axis = .vertical
            row.spacing = 2
            row.isAccessibilityElement = true
            row.accessibilityLabel = "\(metadata.label): \(metadata.value)"
            metadataStack.addArrangedSubview(row)
        }
    }
}
@MainActor
final class FilesViewController: RefreshingTableViewController {
    private let context: AppContext
    private let owner: String
    private let repository: String
    private let sha: String
    private let branch: String?
    private let commitHeader = CommitHeaderView()
    private var page: CommitDetailsPage?

    init(context: AppContext, owner: String, repository: String, sha: String, branch: String? = nil) {
        self.context = context
        self.owner = owner
        self.repository = repository
        self.sha = sha
        self.branch = branch
        super.init()
        title = "Changed Files"
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }

    override func viewDidLoad() {
        super.viewDidLoad()
        loadContent(refreshing: false)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        guard let header = tableView.tableHeaderView else { return }
        let size = header.systemLayoutSizeFitting(
            CGSize(width: tableView.bounds.width, height: 0),
            withHorizontalFittingPriority: .required,
            verticalFittingPriority: .fittingSizeLevel
        )
        guard header.frame.height != size.height else { return }
        header.frame.size.height = size.height
        tableView.tableHeaderView = header
    }

    override func loadContent(refreshing: Bool) {
        beginLoading(refreshing: refreshing)
        loadingTask?.cancel()
        loadingTask = Task {
            do {
                let page = try await context.core.commitDetails(
                    owner: owner,
                    repository: repository,
                    sha: sha,
                    branch: branch
                )
                self.page = page
                commitHeader.configure(page)
                tableView.tableHeaderView = commitHeader
                tableView.reloadData()
                tableView.backgroundView = page.files.isEmpty
                    ? EmptyBackgroundView(title: "No changed files", detail: "This commit does not contain file changes.")
                    : nil
            } catch {
                if !Task.isCancelled { show(error: error) }
            }
            endLoading()
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        page?.files.count ?? 0
    }

    override func tableView(
        _ tableView: UITableView,
        cellForRowAt indexPath: IndexPath
    ) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "file")
            ?? UITableViewCell(style: .subtitle, reuseIdentifier: "file")
        let row = page!.files[indexPath.row]
        configureTextCell(cell, title: row.path, detail: row.status)
        cell.accessoryType = .disclosureIndicator
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        guard let row = page?.files[indexPath.row] else { return }
        navigationController?.pushViewController(
            DiffViewController(
                context: context,
                source: .commit(
                    owner: owner,
                    repository: repository,
                    sha: sha,
                    path: row.path
                )
            ),
            animated: true
        )
    }
}
