from flask import current_app as app, flash
from flask_admin.actions import action

from feedrsub.admin.views import SecuredModelView
from feedrsub.authors import AuthorParser
from feedrsub.database import db
from feedrsub.models.entry import Entry
from feedrsub.utils.strings import stringify_list


class EntryModelView(SecuredModelView):
    column_exclude_list = [
        "content",
        "summary",
        "emails",
        "created_on",
        "updated_on",
        "guid",
    ]
    column_default_sort = ("published", True)
    column_filters = [
        "feed.title",
        "feed.topic",
        "feed.id",
        "authorstring",
        "link",
        "title",
        "site",
        "guid",
        "id",
        "published",
        "updated",
        "language",
        "authors.name",
        "authors.id",
        "authors.author_maps.author_string",
    ]
    column_searchable_list = ["link", "authorstring", "guid"]
    form_excluded_columns = ["emails"]
    column_list = (
        "id",
        "feed",
        "title",
        "published",
        "updated",
        "link",
        "site",
        "authorstring",
        "original_authorstring",
        "wordcount",
        "language",
    )
    column_labels = dict(
        authorstring="Authorstring",
        original_authorstring="Original Authors",
        wordcount="Words",
    )
    can_view_details = True
    form_ajax_refs = {
        "authors": {"fields": ["name"], "page_size": 20},
        "feed": {"fields": ["topic", "title"], "page_size": 20},
    }

    @action(
        "update_authorstring",
        "Update Authorstring",
        "Are you sure you want to update the Authorstrings for the selected Entries?",
    )
    def update_authorstring(self, ids):
        try:
            entries = Entry.query.filter(Entry.id.in_(ids)).all()
            app.logger.info(
                "Admin Updating Authorstring for Entries: %s", stringify_list(entries)
            )
            for entry in entries:
                entry.create_author_string()
                db.session.add(entry)
            db.session.commit()
            flash(
                f"Authorstrings were successfully updated for {len(ids)} Entries.",
                "success",
            )
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to updated Entry Authorstrings. {ex}", "error")

    @action(
        "reparse_original_authorstring",
        "Reparse Original Authorstring",
        "Are you sure you want to reparse the original authorstring for the selected Entries?",
    )
    def reparse_original_authorstring(self, ids):
        try:
            entries = Entry.query.filter(Entry.id.in_(ids)).all()
            app.logger.info(
                "Admin Reparsing Original Authorstring for Entries: %s",
                stringify_list(entries),
            )
            for entry in entries:
                entry.authors = []
                parser = AuthorParser(author_string=entry.original_authorstring)
                parser.parse()
                authors = parser.match_existing_authors()
                entry.authors = authors
                entry.create_author_string()
                db.session.add(entry)
            db.session.commit()
            flash(
                f"Authorstrings were successfully reparsed for {len(ids)} Entries.",
                "success",
            )
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to reparse Entry Authorstrings. {ex}", "error")

    @action(
        "update_wordcount",
        "Update Wordcount",
        "Are you sure you want to update the Wordcount for the selected Entries?",
    )
    def update_wordcount(self, ids):
        try:
            entries = Entry.query.filter(Entry.id.in_(ids)).all()
            app.logger.info(
                "Admin Updating Wordcount for Entries: %s", stringify_list(entries)
            )
            for entry in entries:
                entry.get_wordcount()
                db.session.add(entry)
            db.session.commit()
            flash(
                f"Wordcount was successfully updated for {len(ids)} Entries.", "success"
            )
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to update Entry Wordcounts. {ex}", "error")

    @action(
        "clean_html",
        "Clean HTML",
        "Are you sure you want to clean the HTML of the selected Entries?",
    )
    def clean_html(self, ids):
        try:
            entries = Entry.query.filter(Entry.id.in_(ids)).all()
            app.logger.info(
                "Admin Cleaning HTML for Entries: %s", stringify_list(entries)
            )
            for entry in entries:
                entry.content = Entry.clean_content(entry.content)
                entry.summary = Entry.clean_content(entry.summary)
                entry.title = Entry.clean_title(entry.title)
                entry.create_summary()
                db.session.add(entry)
            db.session.commit()
            flash(f"HTML was successfully cleaned for {len(ids)} Entries.", "success")
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to clean Entry HTML. {ex}", "error")

    @action(
        "update_site",
        "Update Site",
        "Are you sure you want to update the Site Info of the selected Entries?",
    )
    def update_site(self, ids):
        try:
            entries = Entry.query.filter(Entry.id.in_(ids)).all()
            app.logger.info(
                "Admin Updating Site Info for Entries: %s", stringify_list(entries)
            )
            for entry in entries:
                entry.site = entry.feed.site_name
                db.session.add(entry)
            db.session.commit()
            flash(
                f"Site Info was successfully updated for {len(ids)} Entries.", "success"
            )
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to update Entry Site Info. {ex}", "error")

    @action(
        "update_details",
        "Update All Details",
        "Are you sure you want to update the Authorstring, Site, Wordcount, and Language of the selected Entries?",
    )
    def update_all_details(self, ids):
        try:
            entries = db.session.query(Entry).filter(Entry.id.in_(ids)).all()
            print(entries)
            app.logger.info(
                "Admin Updating all details for Entries: %s", stringify_list(entries)
            )
            for entry in entries:
                entry.create_author_string()
                entry.get_site_name()
                entry.get_wordcount()
                entry.detect_language()
                db.session.add(entry)
            db.session.commit()
            flash(
                f"Details were successfully updated for {len(ids)} Entries.", "success"
            )
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            flash(f"Failed to update Entry Details. {ex}", "error")
