import os
import json

from meltano.core.utils import slugify

from .m5o_collection_parser import M5oCollectionParser, M5oCollectionParserTypes
from .m5o_file_parser import MeltanoAnalysisFileParser


class ReportAlreadyExistsError(Exception):
    """Occurs when a report already exists."""

    def __init__(self, report, field):
        self.report = report
        self.field = field

    @property
    def record(self):
        return self.report


class ReportsService:
    VERSION = "1.0.0"

    def __init__(self, project):
        self.project = project

    def get_reports(self):
        reportsParser = M5oCollectionParser(
            self.project.analyze_dir("reports"), M5oCollectionParserTypes.Report
        )

        return reportsParser.parse()

    def get_report(self, report_id):
        reports = self.get_reports()
        report = next(filter(lambda r: r["id"] == report_id, reports), None)
        return report

    def save_report(self, data):
        if "id" in data:
            existing_report = self.get_report(data["id"])
            if existing_report:
                raise ReportAlreadyExistsError(existing_report, "id")

        name = data["name"]
        slug = slugify(name)
        file_path = self.project.analyze_dir("reports", f"{slug}.report.m5o")

        if os.path.exists(file_path):
            with file_path.open() as f:
                existing_report = json.load(f)
            raise ReportAlreadyExistsError(existing_report, "slug")

        data = MeltanoAnalysisFileParser.fill_base_m5o_dict(
            file_path.relative_to(self.project.root), slug, data
        )
        data["version"] = ReportsService.VERSION

        with file_path.open("w") as f:
            json.dump(data, f)

        return data

    def update_report(self, data):
        id = data["id"]
        existing_report = self.get_report(id)
        slug = existing_report["slug"]

        file_path = self.project.analyze_dir("reports", f"{slug}.report.m5o")

        new_name = data["name"]
        new_slug = slugify(new_name)
        new_file_path = self.project.analyze_dir("reports", f"{new_slug}.report.m5o")
        is_same_file = new_slug == slug
        if not is_same_file and os.path.exists(new_file_path):
            with new_file_path.open() as f:
                existing_report = json.load(f)
            raise ReportAlreadyExistsError(existing_report)

        os.remove(file_path)

        data["slug"] = new_slug
        data["path"] = str(new_file_path.relative_to(self.project.root))
        with new_file_path.open("w") as f:
            json.dump(data, f)

        return data
