''' handle reading a csv from goodreads '''
import csv
import logging

from bookwyrm import models
from bookwyrm.broadcast import broadcast
from bookwyrm.models import ImportJob, ImportItem
from bookwyrm.status import create_notification
from bookwyrm.tasks import app

logger = logging.getLogger(__name__)


def create_job(user, csv_file, include_reviews, privacy):
    ''' check over a csv and creates a database entry for the job'''
    job = ImportJob.objects.create(
        user=user,
        include_reviews=include_reviews,
        privacy=privacy
    )
    for index, entry in enumerate(list(csv.DictReader(csv_file))):
        if not all(x in entry for x in ('ISBN13', 'Title', 'Author')):
            raise ValueError('Author, title, and isbn must be in data.')
        ImportItem(job=job, index=index, data=entry).save()
    return job


def create_retry_job(user, original_job, items):
    ''' retry items that didn't import '''
    job = ImportJob.objects.create(
        user=user,
        include_reviews=original_job.include_reviews,
        privacy=original_job.privacy,
        retry=True
    )
    for item in items:
        ImportItem(job=job, index=item.index, data=item.data).save()
    return job


def start_import(job):
    ''' initalizes a csv import job '''
    result = import_data.delay(job.id)
    job.task_id = result.id
    job.save()


@app.task
def import_data(job_id):
    ''' does the actual lookup work in a celery task '''
    job = ImportJob.objects.get(id=job_id)
    try:
        for item in job.items.all():
            try:
                item.resolve()
            except Exception as e:# pylint: disable=broad-except
                logger.exception(e)
                item.fail_reason = 'Error loading book'
                item.save()
                continue

            if item.book:
                item.save()

                # shelves book and handles reviews
                handle_imported_book(
                    job.user, item, job.include_reviews, job.privacy)
            else:
                item.fail_reason = 'Could not find a match for book'
                item.save()
    finally:
        create_notification(job.user, 'IMPORT', related_import=job)
        job.complete = True
        job.save()


def handle_imported_book(user, item, include_reviews, privacy):
    ''' process a goodreads csv and then post about it '''
    if isinstance(item.book, models.Work):
        item.book = item.book.default_edition
    if not item.book:
        return

    existing_shelf = models.ShelfBook.objects.filter(
        book=item.book, added_by=user).exists()

    # shelve the book if it hasn't been shelved already
    if item.shelf and not existing_shelf:
        desired_shelf = models.Shelf.objects.get(
            identifier=item.shelf,
            user=user
        )
        shelf_book = models.ShelfBook.objects.create(
            book=item.book, shelf=desired_shelf, added_by=user)
        broadcast(user, shelf_book.to_add_activity(user), privacy=privacy)

    for read in item.reads:
        # check for an existing readthrough with the same dates
        if models.ReadThrough.objects.filter(
                user=user, book=item.book,
                start_date=read.start_date,
                finish_date=read.finish_date
            ).exists():
            continue
        read.book = item.book
        read.user = user
        read.save()

    if include_reviews and (item.rating or item.review):
        review_title = 'Review of {!r} on Goodreads'.format(
            item.book.title,
        ) if item.review else ''

        # we don't know the publication date of the review,
        # but "now" is a bad guess
        published_date_guess = item.date_read or item.date_added
        review = models.Review.objects.create(
            user=user,
            book=item.book,
            name=review_title,
            content=item.review,
            rating=item.rating,
            published_date=published_date_guess,
            privacy=privacy,
        )
        # we don't need to send out pure activities because non-bookwyrm
        # instances don't need this data
        broadcast(user, review.to_create_activity(user), privacy=privacy)