/* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.model;

import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.constants.Field.*;

import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.api.Owner;
import de.srsoftware.umbrella.core.constants.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import org.json.JSONObject;

public class Item implements Mappable {
	private long id, ownerNumber; // id is the database key, number the owner-relative id
	private Owner owner;
	private String code, description, name;
	private Location location;
	private Collection<Property> properties;
	private Set<String> dirtyFields = new HashSet<>();

	public Item(long id, Owner owner, long ownerNumber, Location location, String code, String name, String description) {
		this.id          = id;
		this.owner       = owner;
		this.ownerNumber = ownerNumber;
		this.location    = location;
		this.code        = code;
		this.name        = name;
		this.description = description;
		this.properties  = new HashSet<>();
	}

	public Item clear() {
		dirtyFields.clear();
		return this;
	}

	public String code(){
		return code;
	}

	public String description(){
		return description;
	}

	public boolean isDirty(){
		return !dirtyFields.isEmpty();
	}

	public long id(){
		return id;
	}

	public Item id(long newVal) {
		id = newVal;
		return this;
	}

	public Location location(){
		return location;
	}

	public Item location(Location newVal) {
		location = newVal;
		dirtyFields.add(LOCATION);
		return this;
	}

	public String name(){
		return name;
	}

	public static Item of(ResultSet rs) throws SQLException {
		var id          = rs.getLong(ID);
		var owner       = OwnerRef.of(rs);
		var ownerNumber = rs.getLong(OWNER_NUMBER);
		var location    = Location.of(rs);
		var code        = rs.getString(Field.CODE);
		var name        = rs.getString(NAME);
		var description = rs.getString(DESCRIPTION);
		return new Item(id, owner, ownerNumber, location, code, name, description);
	}

	public Owner owner(){
		return owner;
	}

	public long ownerNumber(){
		return ownerNumber;
	}

	public void ownerNumber(long newVal) {
		ownerNumber = newVal;
	}

	public Item patch(JSONObject json) {
		for (var field : json.keySet()){
			var known = true;
			switch (field) {
				case Field.CODE:
					code = json.getString(field);
					break;
				case NAME:
					name = json.getString(field);
					break;
				case DESCRIPTION:
					description = json.getString(field);
					break;
				default:
					known = false;
			}
			if (known) dirtyFields.add(field);
		}
		return this;
	}

	public Collection<Property> properties() {
		return properties;
	}

	@Override
	public Map<String, Object> toMap() {
		var map = new HashMap<String,Object>();
		map.put(OWNER,owner.toMap());
		map.put(ID,id);
		map.put(LOCATION,location.toMap());
		map.put(Field.CODE,code);
		map.put(NAME,name);
		map.put(DESCRIPTION,mapMarkdown(description));
		map.put(OWNER_NUMBER,ownerNumber);
		if (properties != null) map.put(PROPERTIES,properties.stream().map(Property::toMap).toList());
		return map;
	}

	@Override
	public String toString() {
		return name;
	}
}
