import {
	CreateConversationStore,
	SendMessageStore,
	DeleteMessageStore,
	MarkConversationAsReadStore,
	ArchiveConversationStore,
	MuteConversationStore,
	DeleteConversationStore
} from '$houdini';
import type { GetMyConversations$result, GetConversation$result } from '$houdini';
import type { AccountAddressInfo, CustomerInfo } from '$lib/utils/lookup';
import { formatDate } from '$lib/utils/date';
import { toGlobalId } from '$lib/utils/relay';

// Type aliases for convenience
export type ConversationEdge = NonNullable<
	NonNullable<GetMyConversations$result['getMyConversations']>['edges']
>[number];
export type Conversation = NonNullable<ConversationEdge>['node'];
export type ConversationDetail = NonNullable<GetConversation$result['conversation']>;
export type Message = NonNullable<ConversationDetail['messages']>[number];
export type Participant = NonNullable<ConversationDetail['participants']>[number];
export type ParticipantProfile = NonNullable<Participant['participant']>;

// Conversation type labels
const CONVERSATION_TYPE_LABELS: Record<string, string> = {
	DIRECT: 'Direct',
	GROUP: 'Group',
	SUPPORT: 'Support'
};

// Mutation stores (singleton instances)
const createConversationStore = new CreateConversationStore();
const sendMessageStore = new SendMessageStore();
const deleteMessageStore = new DeleteMessageStore();
const markAsReadStore = new MarkConversationAsReadStore();
const archiveConversationStore = new ArchiveConversationStore();
const muteConversationStore = new MuteConversationStore();
const deleteConversationStore = new DeleteConversationStore();

/**
 * Check if a string is a valid UUID format
 */
function isUuid(str: string): boolean {
	const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
	return uuidRegex.test(str);
}

/**
 * Convert participant ID to Global ID format if needed
 * Backend expects Global IDs (base64 encoded), not raw UUIDs
 */
function ensureGlobalId(id: string): string {
	if (!id) return id;

	// If it's a UUID, convert to Global ID (assume TeamProfileType)
	if (isUuid(id)) {
		return toGlobalId('TeamProfileType', id);
	}

	// Already a Global ID (base64 encoded strings are typically longer and may contain =)
	return id;
}

/**
 * Create a new conversation
 */
export async function createConversation(input: {
	subject: string;
	conversationType: string;
	participantIds: string[];
	entityType?: string;
	entityId?: string;
	metadata?: string;
}) {
	// Convert participant IDs to Global IDs if they're UUIDs
	// Backend expects GlobalID format (base64 encoded)
	const globalParticipantIds = input.participantIds.map(ensureGlobalId);

	const result = await createConversationStore.mutate({
		input: {
			subject: input.subject,
			conversationType: input.conversationType,
			participantIds: globalParticipantIds,
			entityType: input.entityType ?? null,
			entityId: input.entityId ?? null,
			metadata: input.metadata ?? null
		}
	});

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.createConversation;
}

/**
 * Send a message in a conversation
 */
export async function sendMessage(input: {
	conversationId: string;
	body: string;
	replyToId?: string;
	attachments?: string;
	metadata?: string;
}) {
	const result = await sendMessageStore.mutate({
		input: {
			conversationId: input.conversationId,
			body: input.body,
			replyToId: input.replyToId ?? null,
			attachments: input.attachments ?? null,
			metadata: input.metadata ?? null
		}
	});

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.sendMessage;
}

/**
 * Delete a message
 */
export async function deleteMessage(id: string) {
	const result = await deleteMessageStore.mutate({ id });

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.deleteMessage;
}

/**
 * Mark a conversation as read
 */
export async function markAsRead(conversationId: string) {
	const result = await markAsReadStore.mutate({
		input: { conversationId }
	});

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.markConversationAsRead;
}

/**
 * Archive or unarchive a conversation
 */
export async function archiveConversation(conversationId: string, isArchived: boolean) {
	const result = await archiveConversationStore.mutate({
		input: { conversationId, isArchived }
	});

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.archiveConversation;
}

/**
 * Mute or unmute a conversation
 */
export async function muteConversation(conversationId: string, isMuted: boolean) {
	const result = await muteConversationStore.mutate({
		input: { conversationId, isMuted }
	});

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.muteConversation;
}

/**
 * Delete a conversation
 */
export async function deleteConversation(id: string) {
	const result = await deleteConversationStore.mutate({ id });

	if (result.errors?.length) {
		throw new Error(result.errors[0].message);
	}

	return result.data?.deleteConversation;
}

// Minimal profile type for name extraction
type ProfileWithName = {
	teamProfile?: { id?: string; fullName?: string | null } | null;
	customerProfile?: { id?: string; fullName?: string | null } | null;
};

/**
 * Get display name from participant profile
 */
export function getParticipantName(participant: ProfileWithName | null | undefined): string {
	if (!participant) return 'Unknown';

	if (participant.teamProfile) {
		return participant.teamProfile.fullName ?? 'Team Member';
	}

	if (participant.customerProfile) {
		return participant.customerProfile.fullName ?? 'Customer';
	}

	return 'Unknown';
}

/**
 * Get sender name from message sender
 */
export function getSenderName(sender: Message['sender'] | null | undefined): string {
	if (!sender) return 'Unknown';

	if (sender.teamProfile) {
		return sender.teamProfile.fullName ?? 'Team Member';
	}

	if (sender.customerProfile) {
		return sender.customerProfile.fullName ?? 'Customer';
	}

	return 'Unknown';
}

/**
 * Get sender ID from message sender
 */
export function getSenderId(sender: Message['sender'] | null | undefined): string | null {
	if (!sender) return null;

	if (sender.teamProfile) {
		return sender.teamProfile.id;
	}

	if (sender.customerProfile) {
		return sender.customerProfile.id;
	}

	return null;
}

/**
 * Get conversation type label
 */
export function getConversationTypeLabel(type: string | null | undefined): string {
	if (!type) return 'Message';
	return CONVERSATION_TYPE_LABELS[type] ?? type;
}

interface EntityDisplayOptions {
	accountLookup?: Map<string, AccountAddressInfo>;
	customerLookup?: Map<string, CustomerInfo>;
	userType?: 'team' | 'customer';
}

/**
 * Get entity display info from conversation
 * - Service: "<Date> - <Account Name>"
 * - Project: "<Date> - <Name> - <Account Name>" or "<Date> - <Name> - <Customer Name>"
 */
export function getEntityDisplay(
	entity: ConversationDetail['entity'] | null | undefined,
	options: EntityDisplayOptions = {}
): {
	type: string;
	name: string;
	id: string;
	link: string | null;
} | null {
	if (!entity) return null;

	const { entityType, entityId } = entity;
	const { accountLookup, customerLookup, userType } = options;

	// Determine base path based on user type
	const basePath = userType === 'customer' ? '/customer' : '/team';

	if (entity.service) {
		const service = entity.service;
		const date = formatDate(service.date) || 'Service';

		// Look up account name via accountAddressId
		let accountName = '';
		if (accountLookup && service.accountAddressId) {
			const accountInfo = accountLookup.get(service.accountAddressId);
			if (accountInfo) {
				accountName = accountInfo.accountName;
			}
		}

		const displayName = accountName ? `${date} - ${accountName}` : date;

		// For customers, link to schedule (they can navigate to history if needed)
		// For team, always use /team/services
		const serviceLink =
			userType === 'customer'
				? `/customer/schedule/service/${service.id}`
				: `/team/services/${service.id}`;

		return {
			type: 'Service',
			name: displayName,
			id: service.id,
			link: serviceLink
		};
	}

	if (entity.project) {
		const project = entity.project;
		const date = formatDate(project.date) || '';
		const projectName = project.name || 'Project';

		// Look up account name via accountAddressId, or customer name via customerId
		let ownerName = '';
		if (accountLookup && project.accountAddressId) {
			const accountInfo = accountLookup.get(project.accountAddressId);
			if (accountInfo) {
				ownerName = accountInfo.accountName;
			}
		} else if (customerLookup && project.customerId) {
			const customerInfo = customerLookup.get(project.customerId);
			if (customerInfo) {
				ownerName = customerInfo.customerName;
			}
		}

		const parts = [date, projectName, ownerName].filter(Boolean);
		const displayName = parts.join(' - ');

		// For customers, link to schedule (they can navigate to history if needed)
		// For team, always use /team/projects
		const projectLink =
			userType === 'customer'
				? `/customer/schedule/project/${project.id}`
				: `/team/projects/${project.id}`;

		return {
			type: 'Project',
			name: displayName,
			id: project.id,
			link: projectLink
		};
	}

	if (entity.account) {
		return {
			type: 'Account',
			name: entity.account.name ?? 'Account',
			id: entity.account.id,
			link: `${basePath}/accounts/${entity.account.id}`
		};
	}

	if (entity.customer) {
		return {
			type: 'Customer',
			name: entity.customer.name ?? 'Customer',
			id: entity.customer.id,
			link: null
		};
	}

	// Fallback to entity type and ID
	if (entityType && entityId) {
		return {
			type: entityType,
			name: entityType,
			id: entityId,
			link: null
		};
	}

	return null;
}

/**
 * Format count for display (99+ for large numbers)
 */
export function formatCount(count: number): string {
	if (count <= 0) return '';
	if (count > 99) return '99+';
	return count.toString();
}

// Minimal participant type for name extraction
type ParticipantWithProfile = {
	participant: {
		teamProfile?: { id: string; fullName?: string | null } | null;
		customerProfile?: { id: string; fullName?: string | null } | null;
	};
};

/**
 * Get list of participant names (excluding current user)
 */
export function getParticipantNames(
	participants: ParticipantWithProfile[] | null | undefined,
	currentUserId?: string,
	maxNames: number = 3
): string {
	if (!participants || participants.length === 0) return '';

	const names = participants
		.map((p) => {
			const profile = p.participant;
			const id = profile?.teamProfile?.id ?? profile?.customerProfile?.id;

			// Skip current user
			if (currentUserId && id === currentUserId) return null;

			return getParticipantName(profile);
		})
		.filter((name): name is string => name !== null);

	if (names.length === 0) return '';

	if (names.length <= maxNames) {
		return names.join(', ');
	}

	const displayNames = names.slice(0, maxNames);
	const remaining = names.length - maxNames;
	return `${displayNames.join(', ')} +${remaining} more`;
}

/**
 * Get last message preview
 */
export function getLastMessagePreview(
	messages: Conversation['messages'] | null | undefined,
	maxLength: number = 50
): string {
	if (!messages || messages.length === 0) return 'No messages yet';

	const lastMessage = messages[0];
	if (!lastMessage?.body) return 'No messages yet';

	const body = lastMessage.body;
	if (body.length <= maxLength) return body;

	return body.substring(0, maxLength) + '...';
}
