using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

using Monitoring.Common;
using Monitoring.Controllers;
using Monitoring.Core.Domain;
using Monitoring.Core.Domain.AssetManagement;
using Monitoring.Extensions;
using Monitoring.Features.Photos.CreatePhoto;
using Monitoring.Features.Photos.GetPhotoList;
using Monitoring.Features.Photos.UpdatePhoto;
using Monitoring.Infrastructure.Data;
using Monitoring.Models;
using Monitoring.Services;

namespace Monitoring.Features.Photos;
[Route("api/photos")]
[Authorize(Roles = $"{Roles.Manager},{Roles.Watcher}")]
public class PhotosController(
	DataContext dataContext,
	INotificationService notificationService,
	UsersService usersService
) : BaseController
{
	[HttpGet(Name = "GetPhotoList")]
	[ProducesResponseType<TableDataResponseModel<PhotoModel>>(StatusCodes.Status200OK)]
	public async Task<IActionResult> Get([FromQuery] GetPhotoListRequest request, CancellationToken cancellationToken)
	{
		var assetId = new AssetId(request.AssetId);
		return Ok(await dataContext.Photos
			.Where(x => x.AssetId == assetId &&
				x.Asset!.Organization!.Members!.Any(x => x.UserId == UserId))
			.GetTable(request, PhotoModel.Projection, cancellationToken));
	}

	[HttpGet("{id:guid}", Name = "GetPhoto")]
	[ProducesResponseType<PhotoModel>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Get(Guid id, CancellationToken cancellationToken)
	{
		var model = await dataContext.Photos
			.Where(x => x.Id == id &&
				x.Asset!.Organization!.Members!.Any(x => x.UserId == UserId))
			.Select(PhotoModel.Projection)
			.FirstOrDefaultAsync(cancellationToken);
		return model is null ? NotFound(nameof(Photo)) : Ok(model);
	}

	[HttpPost(Name = "CreatePhoto")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType<PhotoModel>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Create(CreatePhotoRequest request, CancellationToken cancellationToken)
	{
		var assetId = new AssetId(request.AssetId);
		var asset = await dataContext.Assets
			.FirstOrDefaultAsync(x => x.Id == assetId &&
				x.Organization!.Members!.Any(member => member.UserId == UserId), cancellationToken);
		if (asset is null)
		{
			return NotFound(nameof(Asset));
		}

		Photo photo = new()
		{
			Asset = asset,
			Name = request.Name,
			Description = request.Description,
			Base64 = request.Base64,
		};

		_ = await dataContext.Photos.AddAsync(photo, cancellationToken);
		_ = await dataContext.SaveChangesAsync(cancellationToken);

		var model = await dataContext.Photos
			.Where(x => x.Id == photo.Id &&
				x.Asset!.Organization!.Members!.Any(x => x.UserId == UserId))
			.Select(PhotoModel.Projection)
			.FirstAsync(cancellationToken);

		await notificationService.NotifyUsers(
			await usersService.GetUserIdListByOrganization(asset.OrganizationId, cancellationToken),
			"PHOTOS.CREATED",
			model,
			cancellationToken
		);

		return Ok(model);
	}

	[HttpPut("{id:guid}", Name = "UpdatePhoto")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType(StatusCodes.Status204NoContent)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Update(Guid id, UpdatePhotoRequest request, CancellationToken cancellationToken)
	{
		var photo = await dataContext.Photos
			.Include(x => x.Asset!)
			.FirstOrDefaultAsync(x => x.Id == id &&
				x.Asset!.Organization!.Members!.Any(member => member.UserId == UserId), cancellationToken);
		if (photo is null)
		{
			return NotFound(nameof(Photo));
		}

		photo.Name = request.Name;
		photo.Description = request.Description;
		// photo.Base64 = await fileService.Update(photo.Base64, request.Name, Convert.FromBase64String(request.Base64Image), cancellationToken);
		photo.Base64 = request.Base64;

		_ = await dataContext.SaveChangesAsync(cancellationToken);

		await notificationService.NotifyUsers(
			await usersService.GetUserIdListByOrganization(photo.Asset!.OrganizationId, cancellationToken),
			"PHOTOS.UPDATED",
			photo,
			cancellationToken
		);

		return NoContent();
	}

	[HttpDelete("{id:guid}", Name = "DeletePhoto")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType(StatusCodes.Status204NoContent)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Delete(Guid id, CancellationToken cancellationToken)
	{
		var photo = await dataContext.Photos
			.Include(x => x.Asset!)
			.FirstOrDefaultAsync(x => x.Id == id &&
				x.Asset!.Organization!.Members!.Any(member => member.UserId == UserId), cancellationToken);
		if (photo is null)
		{
			return NotFound(nameof(Photo));
		}

		var organizationId = photo.Asset!.OrganizationId;

		// await fileService.Delete(photo.Base64, cancellationToken);

		_ = dataContext.Photos.Remove(photo);
		_ = await dataContext.SaveChangesAsync(cancellationToken);

		await notificationService.NotifyUsers(
			await usersService.GetUserIdListByOrganization(organizationId, cancellationToken),
			"PHOTOS.DELETED",
			photo,
			cancellationToken
		);

		return NoContent();
	}
}
