/*
 * Copyright 2021-2025 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.opentest4j.reporting.tooling.core.htmlreport;

import org.apiguardian.api.API;
import org.opentest4j.reporting.events.core.Infrastructure;
import org.opentest4j.reporting.events.git.Branch;
import org.opentest4j.reporting.events.git.Commit;
import org.opentest4j.reporting.events.git.Repository;
import org.opentest4j.reporting.events.git.Status;
import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor;
import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs;
import org.opentest4j.reporting.tooling.spi.htmlreport.PreFormattedOutput;
import org.opentest4j.reporting.tooling.spi.htmlreport.Section;
import org.opentest4j.reporting.tooling.spi.htmlreport.Subsections;
import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static org.apiguardian.api.API.Status.INTERNAL;
import static org.opentest4j.reporting.tooling.core.htmlreport.CoreContributor.addToTable;
import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChild;
import static org.opentest4j.reporting.tooling.core.util.DomUtils.getAttribute;

/**
 * Contributes sections to the HTML report elements in the git schema.
 *
 * @since 0.2.0
 */
@API(status = INTERNAL, since = "0.2.0")
public class GitContributor implements Contributor {

	/**
	 * Create a new instance.
	 */
	public GitContributor() {
	}

	@Override
	public List<Section> contributeSectionsForExecution(Context context) {
		var sections = new ArrayList<Section>();
		findChild(context.element(), Infrastructure.ELEMENT) //
				.flatMap(GitContributor::createGitSection) //
				.ifPresent(sections::add);
		return sections;
	}

	private static Optional<Section> createGitSection(Node infrastructure) {

		var table = KeyValuePairs.builder();

		findChild(infrastructure, Repository.ELEMENT) //
				.ifPresent(repository -> addToTable(getAttribute(repository, Repository.ORIGIN_URL), "Origin",
					table::putContent));

		addToTable(infrastructure, Branch.ELEMENT, "Branch", table::putContent);
		addToTable(infrastructure, Commit.ELEMENT, "Commit hash", table::putContent);

		var status = findChild(infrastructure, Status.ELEMENT);
		status.ifPresent(it -> addToTable(getAttribute(it, Status.CLEAN), "Clean", table::putContent));
		var statusBlock = status.map(Node::getTextContent) //
				.filter(it -> !it.isBlank()) //
				.map(statusText -> {
					var codeBlock = PreFormattedOutput.builder().content(statusText).build();
					var statusSubsection = Section.builder().title("Status of working tree").addBlock(
						codeBlock).build();
					return Subsections.builder().addContent(statusSubsection).build();
				});

		var sectionBuilder = Section.builder().title("Git").order(15);

		var keyValuePairs = table.build();
		if (!keyValuePairs.getContent().isEmpty()) {
			sectionBuilder.addBlock(keyValuePairs);
		}

		statusBlock.ifPresent(sectionBuilder::addBlock);

		var section = sectionBuilder.build();

		return section.getBlocks().isEmpty() ? Optional.empty() : Optional.of(section);
	}
}
