﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using BookRepo.Data.Entities;
using BookRepo.DataMiner.BookFinder;
using BookRepo.DataMiner.ISBNdb;
using BookRepo.DataMiner.OpenLibrary;

namespace BookRepo.DataMiner {
	public class DataScraperFactoryImpl : IDataScraperFactory {

		#region IDataScraperFactory Implementation

		public async Task<ExtnBookData> GetBookDataFromWeb(string isbn) {
			var retval = new ExtnBookData { Isbn = isbn, ImportedOn = DateTime.UtcNow };
			var extnSrc = ForBookFinder();
			retval.BookFinder = await extnSrc.GetData(isbn);
			extnSrc = ForIsbnDb();
			retval.IsbnDb = await extnSrc.GetData(isbn);
			extnSrc = ForOpenLibrary();
			retval.OpenLibrary = await extnSrc.GetData(isbn);
			return retval;
		}

		public async Task<ExtnBookData> GetBookDataFromBookFinder(string isbn) {
			var retval = new ExtnBookData { Isbn = isbn, ImportedOn = DateTime.UtcNow };
			var extnSrc = ForBookFinder();
			retval.BookFinder = await extnSrc.GetData(isbn);
			return retval;
		}

		public async Task<ExtnBookData> GetBookDataFromIsbnDb(ExtnBookData raw) {
			var extnSrc = ForIsbnDb();
			raw.IsbnDb = await extnSrc.GetData(raw.Isbn);
			return raw;
		}

		public async Task<ExtnBookData> GetBookDataFromOpenLibrary(ExtnBookData raw) {
			var extnSrc = ForOpenLibrary();
			raw.OpenLibrary = await extnSrc.GetData(raw.Isbn);
			return raw;
		}

		public void ReparseBookData(ExtnBookData raw) {
			IDataScraper scraper;

			if (raw.BookFinder?.RawHtml != null) {
				scraper = ForBookFinder();
				raw.BookFinder = scraper.Reparse(raw.BookFinder.RawHtml);
			}

			if (raw.IsbnDb?.RawHtml != null) {
				scraper = ForIsbnDb();
				raw.IsbnDb = scraper.Reparse(raw.IsbnDb.RawHtml);
			}

			if (raw.OpenLibrary?.RawHtml != null) {
				scraper = ForOpenLibrary();
				raw.OpenLibrary = scraper.Reparse(raw.OpenLibrary.RawHtml);
			}
		}

		public async Task<Book> CreateBook(ExtnBookData raw) {
			var pubOnRaw = StringPicker(raw.OpenLibrary?.DatePublished, raw.BookFinder?.DatePublished, raw.IsbnDb?.DatePublished);
			var pubOn = pubOnRaw != null ? DateTime.TryParse(pubOnRaw, out var dt) ? dt : (DateTime?)null : (DateTime?)null;

			List<byte>? cover = null;
			var coverUrl = raw.OpenLibrary?.CoverImageUrl ?? raw.BookFinder?.CoverImageUrl ?? raw.IsbnDb?.CoverImageUrl;
			if (coverUrl != null) {
				using var http = new HttpClient();
				var msg = await http.GetAsync(coverUrl);
				if (msg.IsSuccessStatusCode) {
					var img = await msg.Content.ReadAsByteArrayAsync();
					if (img.Length > 0) {
						cover = new List<byte>(img);
					}
				}
			}

			var retval = new Book {
				Isbn = raw.Isbn,
				CreatedOn = DateTime.UtcNow,
				Title = StringPicker(raw.OpenLibrary?.Title, raw.BookFinder?.Title, raw.IsbnDb?.Title) ?? "Unknown",
				Author = StringPicker(raw.OpenLibrary?.Author, raw.BookFinder?.Author, raw.IsbnDb?.Author),
				Publisher = StringPicker(raw.OpenLibrary?.Publisher, raw.BookFinder?.Publisher, raw.IsbnDb?.Publisher),
				Description = StringPicker(raw.BookFinder?.Description, raw.OpenLibrary?.Description, raw.IsbnDb?.Description),
				PublishedOnRaw = pubOnRaw,
				NumPages = raw.OpenLibrary?.NumPages ?? raw.BookFinder?.NumPages ?? raw.IsbnDb?.NumPages,
				PublishedOn = pubOn,
				Cover = cover
			};

			return retval;
		}

		#endregion

		private static IDataScraper ForBookFinder() => new ScraperBookFinder();

		private static IDataScraper ForIsbnDb() => new ScraperIsbn();

		private static IDataScraper ForOpenLibrary() => new ScraperOpenLib();

		private static string? StringPicker(string? openLibrary, string? bookFinder, string? isbnDb) {
			var olLen = openLibrary?.Length ?? 0;
			var bfLen = bookFinder?.Length ?? 0;
			var ibLen = isbnDb?.Length ?? 0;
			if (ibLen > olLen && ibLen > bfLen) return isbnDb;
			if (bfLen > olLen) return bookFinder;
			return openLibrary;
		}
	}
}
