package persistence.link;

import category.CategoryId;
import link.Link;
import link.LinkId;
import link.LinkUrl;
import persistence.csv.CSVSerializable;
import persistence.tag.TagEntity;
import user.Username;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class LinkEntity implements CSVSerializable {

	private final Integer id;
	private final String creator;
	private final String url;
	private final Set<Integer> categoryIds;
	private final Set<TagEntity> tags;

	public LinkEntity(Integer id, String creator, String url, Set<Integer> categoryIds, Set<TagEntity> tags) {
		this.id = id;
		this.creator = creator;
		this.url = url;
		this.categoryIds = categoryIds;
		this.tags = tags;
	}

	public LinkEntity(String[] fields) {
		this.id = Integer.parseInt(fields[0]);
		this.creator = fields[1];
		this.url = fields[2];
		this.categoryIds = fields.length > 3 ?
				(Arrays.stream(fields[3].split(CSVSerializable.listSeperator)).map(Integer::parseInt)).collect(
						Collectors.toSet()) : Set.of();

		this.tags = fields.length > 4 ?  (Arrays
				.stream(fields[4].split(CSVSerializable.listSeperator))
				.map(TagEntity::new)).collect(Collectors.toSet()) : Set.of();
	}

	public LinkEntity(Link link) {
		this.id = link.getId().id();
		this.creator = link.getCreator().username();
		this.url = link.getUrl().toString();
		this.categoryIds = link.getCategoryIds().stream().map(CategoryId::id).collect(Collectors.toSet());
		this.tags = link.getTags().stream().map(TagEntity::new).collect(Collectors.toSet());
	}

	public Link toLink() {
		return new Link(new LinkId(id),
		                new Username(creator),
		                new LinkUrl(url),
		                categoryIds.stream().map(CategoryId::new).collect(Collectors.toSet()),
		                tags.stream().map(TagEntity::toTag).collect(Collectors.toSet()));
	}

	@Override
	public String[] getHeaders() {
		return new String[]{"id", "creator", "url", "categoryIds", "tagIds"};
	}

	@Override
	public String toCSVString() {
		return id + CSVSerializable.seperator + creator + CSVSerializable.seperator + url + CSVSerializable.seperator + String.join(
				CSVSerializable.listSeperator,
				categoryIds
						.stream()
						.map(Object::toString)
						.collect(Collectors.toSet())) + CSVSerializable.seperator + String.join(CSVSerializable.listSeperator,
		                                                                                        tags
				                                                                                        .stream()
				                                                                                        .map(TagEntity::toCSVString)
				                                                                                        .collect(
						                                                                                        Collectors.toSet()));
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		LinkEntity that = (LinkEntity) o;

		if (!Objects.equals(id, that.id)) return false;
		if (!Objects.equals(creator, that.creator)) return false;
		if (!Objects.equals(url, that.url)) return false;
		if (!Objects.equals(categoryIds, that.categoryIds)) return false;
		return Objects.equals(tags, that.tags);
	}

	@Override
	public int hashCode() {
		int result = id != null ? id.hashCode() : 0;
		result = 31 * result + (creator != null ? creator.hashCode() : 0);
		result = 31 * result + (url != null ? url.hashCode() : 0);
		result = 31 * result + (categoryIds != null ? categoryIds.hashCode() : 0);
		result = 31 * result + (tags != null ? tags.hashCode() : 0);
		return result;
	}
}
