# -*- coding: utf-8 -*-
# Copyright (C) 2023-2025 TUD | ZIH
# ralf.klammer@tu-dresden.de
# moritz.wilhelm@tu-dresden.de

import logging

from .collection import CollectionModeler
from .util import RenderBase
from .yaml import CollectionConfigTemplate, ProjectConfig


log = logging.getLogger(__name__)


class Project(RenderBase):

    def __init__(self, projectpath, templates=None, *args, **kw):
        super().__init__(projectpath, templates=templates)
        self.templates = templates
        self.collectors = []
        self._project_config = None
        self._avatar = None
        self._xslt = None
        self._requirements = None

    @property
    def requirements(self):
        if self._requirements is None:
            self._requirements = CollectionConfigTemplate(
                projectpath=self.projectpath
            ).extracted_requirements
        return self._requirements

    @property
    def project_config(self):
        if self._project_config is None:
            self._project_config = ProjectConfig(self.projectpath)
        return self._project_config

    def render_project(self, validate=True, export=True):

        for subproject in self.project_config.content["subprojects"]:
            collection = CollectionModeler(
                subproject, self.projectpath, templates=self.templates
            )
            if validate:
                collection.validate_collection(self.requirements)
            collection.render_collection()
            self.project_config.other_files.add_facets(collection.facets)
            if export:
                collection.export()
        self.project_config.other_files.render_all()

    def _validate_project(self):
        results = {"ok": [], "warning": [], "error": []}
        # Check if xslt, avatar and description are set
        if self.project_config.xslt:
            results["ok"].append("XSLT is set.")
        else:
            results["warning"].append("XSLT is not set.")

        if self.project_config.avatar:
            if self.project_config.avatar == "avatar.png":
                results["warning"].append("Avatar is set to default.")
            else:
                results["ok"].append("Avatar is set.")
        else:
            results["warning"].append("Avatar is not set.")

        if self.project_config.description:
            results["ok"].append("Description is set.")
        else:
            results["warning"].append("Description is not set.")

        # Check if at least one collector is set
        if not self.project_config.collectors:
            results["error"].append("No collectors are set.")
        else:
            results["ok"].append("At least one collector is set.")
            # Check if each collector has fullname and id/url
            for collector in self.project_config.collectors:
                if not collector.get("url"):
                    results["warning"].append(
                        f"Collector {collector['name']} has no URL defined!"
                    )
        return results

    def validate(self):
        # Structure to store validation results for the project
        # and its subprojects
        validation_results = {
            "project": None,
            "subprojects": [],
            # Flag to indicate if the project is ready for publication
            "ready_for_publication": True,
        }
        # General project validation
        validation_results["project"] = self._validate_project()
        # Validate each subproject
        for subproject in self.project_config.content["subprojects"]:
            collection = CollectionModeler(
                subproject, self.projectpath, templates=self.templates
            )
            sp_validation = collection.validate_collection(self.requirements)
            # Add validation results for this subproject
            _dict = {
                "subproject": subproject,
                "files": sp_validation["files"],
                "stats": sp_validation["stats"],
                "title": subproject["name"],
                "file_attributes": collection.get_file_attributes(),
            }
            validation_results["subprojects"].append(_dict)
            # Check if there are errors in the subproject validation
            if sp_validation["stats"]["error"] > 0:
                validation_results["ready_for_publication"] = False

        return validation_results

    def export(self):

        for subproject in self.project_config.content["subprojects"]:
            collection = CollectionModeler(
                subproject, self.projectpath, templates=self.templates
            )
            collection.export()

    def collection_publication_status_set(
        self,
        collection_name,
        status,
    ):

        message = ""
        for obj in status.publish_object:
            if obj.error:
                message += (
                    f"Object {obj.name} has error: {obj.error[0].message}\n"
                )
            if obj.warning:
                message += f"Object {obj.name} has warning: {obj.warning[0].message}\n"

        process_status = status.publish_status.process_status
        publish_status = status.publish_status

        for subproject in self.project_config.content["subprojects"]:
            if subproject["name"] == collection_name:
                if "publication" not in subproject:
                    subproject["publication"] = {
                        "dryrun": {},
                        "publish": {},
                    }
                if status.dry_run:
                    _obj = subproject["publication"]["dryrun"]
                else:
                    _obj = subproject["publication"]["publish"]
                _obj["status"] = {
                    "name": process_status.name,
                    "value": process_status.value,
                }
                _obj["message"] = message
                _obj["progress"] = publish_status.progress
                self.project_config.save()

    def collection_publication_status_get(self, collection_name, dry_run=None):
        for subproject in self.project_config.content["subprojects"]:
            if subproject["name"] == collection_name:
                if "publication" in subproject:
                    if dry_run is None:
                        return subproject["publication"]
                    elif dry_run:
                        return subproject["publication"]["dryrun"]
                    else:
                        return subproject["publication"]["publish"]

    def collection_upload_status_set(
        self, collection_name, status, category="upload"
    ):
        for subproject in self.project_config.content["subprojects"]:
            if subproject["name"] == collection_name:
                if "upload" not in subproject:
                    subproject["upload"] = {}
                _obj = subproject["upload"]
                _obj["status"] = {
                    "name": status.status.name,
                    "value": status.status.value,
                }
                _obj["message"] = str(status.message).replace("'", '"')
                _obj["total"] = status.total
                _obj["completed"] = status.completed
                self.project_config.save()

    def collection_upload_status_get(self, collection_name):
        for subproject in self.project_config.content["subprojects"]:
            if subproject["name"] == collection_name:
                if "upload" in subproject:
                    return subproject["upload"]

    def other_files_upload_status_set(self, status):
        if not self.project_config.content.get("other_files"):
            self.project_config.content["other_files"] = {}
        if not self.project_config.content["other_files"].get("upload"):
            self.project_config.content["other_files"]["upload"] = {}
        _obj = self.project_config.content["other_files"]["upload"]
        _obj["status"] = {
            "name": status.status.name,
            "value": status.status.value,
        }
        _obj["message"] = str(status.message).replace("'", '"')
        _obj["total"] = status.total
        _obj["completed"] = status.completed

        self.project_config.save()

    def other_files_upload_status_get(self):
        if self.project_config.content.get("other_files"):
            if "upload" in self.project_config.content.get("other_files"):
                return self.project_config.content["other_files"]["upload"]

    def other_files_publication_status_set(self, status):
        message = ""
        for obj in status.publish_object:
            if obj.error:
                message += (
                    f"Object {obj.name} has error: {obj.error[0].message}\n"
                )
            if obj.warning:
                message += f"Object {obj.name} has warning: {obj.warning[0].message}\n"

        process_status = status.publish_status.process_status
        publish_status = status.publish_status

        if "publication" not in self.project_config.content["other_files"]:
            self.project_config.content["other_files"]["publication"] = {
                "dryrun": {},
                "publish": {},
            }
        if status.dry_run:
            _obj = self.project_config.content["other_files"]["publication"][
                "dryrun"
            ]
        else:
            _obj = self.project_config.content["other_files"]["publication"][
                "publish"
            ]
        _obj["status"] = {
            "name": process_status.name,
            "value": process_status.value,
        }
        _obj["message"] = message
        _obj["progress"] = publish_status.progress

        self.project_config.save()

    def other_files_publication_status_get(self, dry_run=None):
        if self.project_config.content.get("other_files"):
            if "publication" in self.project_config.content.get("other_files"):
                if dry_run is None:
                    return self.project_config.content["other_files"][
                        "publication"
                    ]
                elif dry_run:
                    return self.project_config.content["other_files"][
                        "publication"
                    ].get("dryrun")
                else:
                    return self.project_config.content["other_files"][
                        "publication"
                    ].get("publish")
