Source: data/Schemas.js

import { Timestamp } from 'firebase/firestore';

/**
 * @typedef {object} AvailabilityObject
 * @property {boolean} active
 * @property {string} day
 * @property {string} from
 * @property {string} do
 */

/**
 * @typedef {object} ProfileObject
 * @property {AvailabilityObject[]} availability
 * @property {string} phoneNumber
 * @property {string} tradingSkill
 */

const defaultAvailability = [
	{ day: 'Mon', from: '09:00', to: '17:00', active: false },
	{ day: 'Tue', from: '09:00', to: '17:00', active: false },
	{ day: 'Wed', from: '09:00', to: '17:00', active: false },
	{ day: 'Thu', from: '09:00', to: '17:00', active: false },
	{ day: 'Fri', from: '09:00', to: '17:00', active: false },
	{ day: 'Sat', from: '10:00', to: '14:00', active: false },
	{ day: 'Sun', from: '10:00', to: '14:00', active: false },
];

export class Profile {
	/**
	 * @param {ProfileObject} rawProfileData
	 */
	constructor(rawProfileData) {
		this.availability = rawProfileData.availability ?? defaultAvailability;
		this.phoneNumber = rawProfileData.phoneNumber ?? '';
		this.tradingSkill = rawProfileData.tradingSkill ?? '';
	}
	toObject() {
		return {
			availability: this.availability,
			phoneNumber: this.phoneNumber,
			tradingSkill: this.tradingSkill,
		};
	}
}

/**
 * @typedef {Object} UserObject
 * @property {string} uid - The user's UID
 * @property {string} bio - The user's bio?
 * @property {string} location - The user's current location
 * @property {String[]} skillsOffered The skills the user is offering
 * @property {String[]} skillsWanted The skills the user is looking for
 * @property {Profile} profile The profile data of the user
 * @property {Number} rating - The user's rating
 * @property {Object} availability - The availability of the user
 * @property {object} profile
 */
export class User {
	/**
	 * @param {UserObject} user
	 */
	constructor(user) {
		this.uid = user.uid;
		this.bio = user.bio;
		this.location = user.location;
		this.skillsOffered = user.skillsOffered;
		this.skillsWanted = user.skillsWanted;
		this.rating = user.rating;
		/** @deprecated See User.profile */
		this.availability = user.availability;
		this.profile = new Profile(user.profile || {});
	}
	/**
	 * Convert this User instance into a plain object for Firestore.
	 * @returns {UserObject}
	 */
	toObject() {
		return {
			uid: this.uid,
			bio: this.bio,
			location: this.location,
			skillsOffered: this.skillsOffered,
			skillsWanted: this.skillsWanted,
			rating: this.rating,
			availability: this.availability,
			profile: this.profile,
		};
	}
}

/**
 * @typedef {'pending' | 'accepted' | 'declined' | 'completed' | 'canceled'} TradeStatus
 */

/**
 * @typedef {Object} TradeObject
 * @property {String} id
 * @property {String} offererId
 * @property {String} receiverId
 * @property {String} offeredSkill
 * @property {String} requestedSkill
 * @property {TradeStatus} tradeStatus
 * @property {String} message
 */

// TODO: Define what a Trade looks like.
export class Trade {
	/**
	 * @param {TradeObject} trade
	 */
	constructor(trade) {
		this.id = trade.id;
		this.offererId = trade.offererId;
		this.receiverId = trade.receiverId;
		this.offeredSkill = trade.offeredSkill;
		this.requestedSkill = trade.requestedSkill;
		this.tradeStatus = trade.tradeStatus;
		this.message = trade.message;
	}
	toObject() {
		return {
			id: this.id,
			offererId: this.offererId,
			receiverId: this.receiverId,
			offeredSkill: this.offeredSkill,
			requestedSkill: this.requestedSkill,
			tradeStatus: this.tradeStatus,
			message: this.message,
		};
	}
}

/**
 * Chat
 */

/**
 * @typedef {Object} ChatParticipant
 * @property {string} displayName
 * @property {string} id
 * @property {string} avatar
 */

/**
 * @typedef {Object} MessageObject
 * @property {string} id
 * @property {ChatParticipant} author
 * @property {string} chatId
 * @property {string} content
 * @property {import('firebase/firestore').Timestamp} timestamp
 */

/**
 * @typedef {Object} ChatObject
 * @property {string} id Generated by Firebase.
 * @property {ChatParticipant} participant1
 * @property {ChatParticipant} participant2
 * @property {MessageObject[]} messages
 * @property {'active' | 'closed'} status
 */

export class Message {
	/**
	 * @param {MessageObject} rawData
	 */
	constructor(rawData) {
		this.id = rawData.id;
		this.author = new ChatUser(rawData.author);
		this.chatId = rawData.chatId;
		this.content = rawData.content;
		this.timestamp = rawData.timestamp ?? Timestamp.now();
	}
	toObject() {
		return {
			id: this.id,
			author: this.author.toObject(),
			chatId: this.chatId,
			content: this.content,
			timestamp: this.timestamp,
		};
	}
}
export class ChatUser {
	/**
	 *
	 * @param {ChatParticipant} rawData
	 */
	constructor(rawData) {
		this.displayName = rawData.displayName;
		this.avatar = rawData.avatar;
		this.id = rawData.id;
	}
	toObject() {
		return {
			displayName: this.displayName,
			avatar: this.avatar,
			id: this.id,
		};
	}
	/**
	 * @param {import('firebase/auth').User} user
	 */
	static from(user) {
		return new ChatUser({
			avatar: user.photoURL,
			displayName: user.displayName,
			id: user.uid,
		});
	}
}

export class Chat {
	/**
	 * @param {ChatObject} rawData - The Firebase Raw Data
	 */
	constructor(rawData) {
		this.id = rawData.id;
		this.participant1 = new ChatUser(rawData.participant1);
		this.participant2 = new ChatUser(rawData.participant2);
		this.status = rawData.status;
		this.messages = [];
		rawData.messages.forEach((msg) => {
			this.messages.push(new Message(msg));
		});
	}
	/**
	 * @param {Message} messageData
	 */
	createMessage(messageData) {
		if (this.status == 'closed') return;

		this.messages.push(messageData);

		// need to push to firebase.
		return;
	}
	close() {
		this.status = 'closed';
		return;
	}
	toObject() {
		const firebaseMessages = [];

		this.messages.forEach((msg) => {
			firebaseMessages.push(msg.toObject());
		});
		return {
			id: this.id,
			participant1: this.participant1.toObject(),
			participant2: this.participant2.toObject(),
			status: this.status,
			messages: firebaseMessages,
		};
	}
}