import { Application } from 'express';
import { Resource } from 'express-automatic-routes';
import { Req, Res } from '#interfaces/IApi';
import verify, { attachPermissions } from '#middlewares/auth';
import { sendSuccess } from '#utils/responseUtils';
import { User } from '#models/User';
import { Resident } from '#models/Resident';
import { ResidentStay } from '#models/ResidentStay';
import { Bed } from '#models/Bed';
import { Room } from '#models/Room';
import { Errors } from '#interfaces/error';
import { FileProvider } from '#providers/FileProvider';
import { getStorageAdapter } from '#services/storage/adapters/StorageFactory';
import Config from '#config';

export default (_express: Application) => {
	const fileProvider = FileProvider.getInstance();
	return <Resource>{
		get: {
			middleware: [verify, attachPermissions],
			handler: async (req: Req, res: Res) => {
				try {
					// `verify` middleware guarantees req.user exists, but JWTPayload only carries
					// id/email/roles — fetch the extra profile fields in a single targeted query
					const user = await User.findByPk(req.user!.id, {
						attributes: ['id', 'email', 'username', 'first_name', 'last_name', 'status', 'avatar_id'],
					});

					if (!user) {
						return res.error(Errors.userNotFound());
					}

					// Fetch resident information based on user_id
					const resident = await Resident.findOne({
						where: {
							user_id: req.user!.id,
							deleted_at: null,
						},
						attributes: [
							'id',
							'full_name',
							'email',
							'phone',
							'id_card',
							'date_of_birth',
							'emergency_contact_name',
							'emergency_contact_phone',
							'emergency_contact_relationship',
							'nationality',
							'job',
							'status',
						],
					});

					// Fetch active rooms for the resident (may be in multiple rooms)
					let rooms: { room_id: string; room_name: string }[] = [];
					if (resident) {
						const activeStays = await ResidentStay.findAll({
							where: { resident_id: resident.id, move_out_at: null },
							attributes: ['bed_id'],
							include: [{
								model: Bed,
								as: 'bed',
								attributes: ['room_id'],
								include: [{
									model: Room,
									as: 'room',
									attributes: ['id', 'name'],
									where: { deleted_at: null },
									required: true,
								}],
								required: true,
							}],
						});
						const seen = new Set<string>();
						for (const stay of activeStays) {
							const room = (stay.bed as any)?.room;
							if (room?.id && !seen.has(room.id)) {
								seen.add(room.id);
								rooms.push({ room_id: room.id, room_name: room.name });
							}
						}
					}

					let avatarUrl: string | null = null;

					// Fetch avatar URL if avatar_id exists
					if (user.avatar_id) {
						try {
							const file = await fileProvider.getById({ id: user.avatar_id });
							if (file) {
								const fileId = user.avatar_id;
								// Local storage: point to /content fallback
								if (file.provider === 'local') {
									avatarUrl = `${Config.server.backendUrl}/api/v1/files/${fileId}/content?mode=view`;
								} else {
									// Cloud storage: generate signed URL
									const storageAdapter = getStorageAdapter();
									const storagePath = file.object_key;
									const url = await storageAdapter.getSignedUrl(storagePath, 3600, 'inline');
									avatarUrl = url;
								}
							}
						} catch (error) {
							// Silently fail if avatar file not found or error occurs
							console.error('[PROFILE] Error fetching avatar URL:', error);
						}
					}

					const responseData = {
						...user.toJSON(),
						username: user.username ?? null,
						first_name: user.first_name ?? null,
						last_name: user.last_name ?? null,
						status: user.status ?? 'active',
						avatar_url: avatarUrl,
						roles: req.user?.roles ?? [],
						permissions: req.user?.permissions ?? [],
						resident: resident ? resident.toJSON() : null,
						rooms,
					};
					return sendSuccess(res, responseData);
				} catch (error) {
					return res.error(error);
				}
			},
		},
	};
};
