﻿extern alias NuGetAlias;
using System;
using System.Linq;
using nH.Context;
using nH.Data.Models;
using nH.Data.Repositories;
using nH.Models;
using nH.Processing.Models;
using nH.Processing.Models.BitBucket;
using nH.Processing.Services;
using NuGetAlias::NuGet.Common;
using NuGetAlias::NuGet.Logging;

namespace nH.Processing.Processors
{
	internal class BitBucketProcessor : BaseProcessor, IProcessor<BitBucketMessage>
	{
		private readonly INhContext _context;
		private readonly IDataRepository<Repository> _dataRepository;
		private readonly IDataRepository<Session> _sessionRepository;
		private readonly ISourceService _sourceService;
		private BbPayload _payload;

		public BitBucketProcessor(INhContext context,
			IDataRepository<Repository> dataRepository,
			IDataRepository<Session> sessionRepository,
			ISourceService sourceService,
			IPublishService publishService,
			IIOService ioService,
			ILogger logger,
			IConsole console)
			: base(context, sessionRepository, publishService, ioService, logger, console)
		{
			_context = context;
			_dataRepository = dataRepository;
			_sessionRepository = sessionRepository;
			_sourceService = sourceService;
		}

		public void Run(BitBucketMessage message)
		{
			if (message == null)
			{
				throw new ArgumentNullException(nameof(message));
			}

			var observedBranch = _context.AppSettings["ObservedBranch"];
			if (observedBranch.Equals(message.Payload.Commit.Branch, StringComparison.InvariantCultureIgnoreCase))
			{
				_payload = message.Payload;
				base.Run(message);
			}
		}

		public override string VersionControl => "bitbucket";

		protected override string GetSources()
		{
			if (_payload.Commit == null)
			{
				return string.Empty;
			}

			var sourceUrl = $"{_payload.CanonUrl}{_payload.Repository.AbsoluteUrl}get/{_payload.Commit.Branch}{SourceExtension}";

			var fileName = _context.Session.Id + SourceExtension;

			return _sourceService.Load(sourceUrl, fileName);
		}

		protected override NhSession CreateSession()
		{
			var repository = EnsureRepository(_payload);

			var session = new Session
			{
				RepositoryId = repository.Id,
				StartDate = DateTime.UtcNow,
				State = SessionState.Ready
			};

			if (_payload.Commit != null)
			{
				session.CommitId = _payload.Commit.RawNode;
				session.CommitMessage = _payload.Commit.Message;
			}

			_sessionRepository.Add(session);

			return new NhSession
			{
				Id = session.Id,
				Name = repository.Name,
				Owner = repository.Owner,
				VersionControl = repository.VersionControl
			};
		}

		private Repository EnsureRepository(BbPayload payload)
		{
			if (payload == null)
			{
				throw new ArgumentNullException(nameof(payload));
			}

			var repository = _dataRepository.GetAll()
				.FirstOrDefault(r => r.Name.Equals(payload.Repository.Name, StringComparison.InvariantCultureIgnoreCase)
									 && r.Owner.Equals(payload.Repository.Owner, StringComparison.InvariantCultureIgnoreCase)
									 && r.VersionControl.Equals(VersionControl, StringComparison.InvariantCultureIgnoreCase));

			return repository ?? CreateRepository(payload);
		}

		private Repository CreateRepository(BbPayload payload)
		{
			var repository = new Repository
			{
				Name = payload.Repository.Name,
				Owner = payload.Repository.Owner,
				Url = $"{payload.CanonUrl}/{payload.Repository.AbsoluteUrl}",
				VersionControl = VersionControl
			};

			return _dataRepository.Add(repository);
		}
	}
}
