import urllib.request
import json
import csv

from pathlib import Path

from texmemo.types import DuplicateBehaviour, Card
from texmemo.errors import AnkiDuplicateError


ANKI_CONNECT_URL = "http://127.0.0.1:8765"


class Uploader():
    def __init__(self, input_path: str,
                 deck_name: str,
                 model_name: str,
                 duplicates: DuplicateBehaviour) -> None:
        self._input = input_path
        self._duplicates = duplicates
        self._deck_name = deck_name
        self._model_name = model_name

    # TODO must refactor ASAP
    def _get_verified_input_path(self, input_path: str) -> Path:
        path = Path(input_path)
        if path.suffix and path.suffix != '.csv':
            raise ValueError(f"Cannot upload {path.suffix} file")
        else:
            path = path.with_suffix(".csv")

        if not path.exists():
            raise FileNotFoundError(f"Cannot find file {path}")

        return path

    def request(self, action, **params):
        return {'action': action, 'params': params, 'version': 6}

    def invoke(self, action, **params):
        requestJson = json.dumps(self.request(
            action, **params)).encode('utf-8')
        request = urllib.request.Request(ANKI_CONNECT_URL, requestJson)
        response = json.load(urllib.request.urlopen(request))
        if len(response) != 2:
            raise Exception(
                "AnkiConnect response has an unexpected number of fields")
        if 'error' not in response:
            raise Exception(
                "AnkiConnect response is missing required error field.")
        if 'result' not in response:
            raise Exception(
                "AnkiConnect response is missing required result field.")
        if response['error'] is not None:
            if response['error'] == "cannot create note because it is a duplicate":
                raise AnkiDuplicateError(response['error'])
            else:
                raise Exception(response['error'])
        return response['result']

    def upload_from_file(self) -> None:
        path = self._get_verified_input_path(self._input)
        cards: list[Card] = []
        with open(path) as f:
            reader = csv.reader(f, delimiter=';')
            for row in reader:
                front, back, tag = row
                cards.append(Card(front=front, back=back, tag=tag))

        for i, card in enumerate(cards):
            params = self._get_note_param_from_card(card)
            try:
                self.invoke('addNote', note=params)
            except AnkiDuplicateError:
                print(f"Skipping card {i+1} due to duplicate...")
            else:
                print(f"Uploaded card {i+1}!")

    def _get_note_param_from_card(self, card: Card):
        return {
            "fields": {
                "Front": card.front,
                "Back": card.back
            },
            "deckName": self._deck_name,
            "modelName": self._model_name,
            "options": {
                "duplicateScope": "deck"
            },
            "tags": [
                card.tag
            ]
        }
