package main;

import category.CategoryRepository;
import category.CategoryUseCase;
import category.RandomCategoryIdGenerator;
import cli.Subcommand;
import cli.category.CategoryCliAdapter;
import cli.category.CategoryCommands;
import cli.link.LinkCliAdapter;
import cli.link.LinkCommands;
import cli.tag.CustomTagsCliAdapter;
import cli.tag.TagCommands;
import link.LinkRepository;
import link.LinkUseCase;
import link.RandomLinkIdGenerator;
import persistence.GenericCSVDAO;
import persistence.category.CSVCategoryPersistenceAdapter;
import persistence.category.CategoryEntity;
import persistence.customTags.CSVCustomTagMatcherPersistenceAdapter;
import persistence.customTags.CustomTagMatcherEntity;
import persistence.link.CSVLinkPersistenceAdapter;
import persistence.link.LinkEntity;
import tag.CustomTagsUseCase;
import tag.TagMatcher;
import tag.TagMatcherRepository;
import tag.TaggingUseCase;
import tag.matcherImplementations.GitHubTagMatcher;

import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;

public class CommandHandler {

	private final HashMap<String, Subcommand> subcommands = new HashMap<>();

	public CommandHandler() {
		this.addSubcommands();
	}

	public void executeCommand(String[] args) {

		if (args.length == 0) {
			printUsage();
			return;
		}

		var command = subcommands.get(args[0]);

		if (command == null) {
			System.out.println("Unkown subcommand!");
			printUsage();
		}

		var output = command.executeSubcommand(Arrays.copyOfRange(args, 1, args.length));
		System.out.println(output);
	}

	private void printUsage() {
		System.out.println("All available subcommands: ");
		subcommands.forEach((name, subcommand) -> System.out.println(System.lineSeparator() + subcommand.getUsage()));
	}

	private void addSubcommands() {

		CategoryRepository categoryRepository =
				new CategoryRepository(new CSVCategoryPersistenceAdapter(new GenericCSVDAO<>(new File("category.csv"),
				                                                                             CategoryEntity::new)));
		CategoryCliAdapter categoryCliAdapter = new CategoryCliAdapter(new CategoryUseCase(categoryRepository,
		                                                                                   new RandomCategoryIdGenerator(
				                                                                                   categoryRepository)));

		var categoryCommands = new CategoryCommands(categoryCliAdapter);
		subcommands.put(categoryCommands.getSubcommand(), categoryCommands);

		LinkRepository linkRepository =
				new LinkRepository(new CSVLinkPersistenceAdapter(new GenericCSVDAO<>(new File("links.csv"),
				                                                                     LinkEntity::new)));
		Set<TagMatcher> staticTagMatchers = Set.of(new GitHubTagMatcher());
		TagMatcherRepository tagMatcherRepository =
				new TagMatcherRepository(new CSVCustomTagMatcherPersistenceAdapter(new GenericCSVDAO<>(
						new File("customtags.csv"),
						CustomTagMatcherEntity::new)), staticTagMatchers);
		TaggingUseCase taggingUseCase =
				new TaggingUseCase(tagMatcherRepository, new RandomLinkIdGenerator(linkRepository));
		LinkCliAdapter linkCliAdapter =
				new LinkCliAdapter(new LinkUseCase(linkRepository,
				                                   categoryRepository,
				                                   taggingUseCase,
				                                   new RandomLinkIdGenerator(linkRepository)));

		var linkCommands = new LinkCommands(linkCliAdapter);
		subcommands.put(linkCommands.getSubcommand(), linkCommands);

		TagCommands tagCommands =
				new TagCommands(new CustomTagsCliAdapter(new CustomTagsUseCase(tagMatcherRepository)));

		subcommands.put(tagCommands.getSubcommand(), tagCommands);

	}
}
