# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2026 Matthias Klumpp <matthias@tenstral.net>
#
# Licensed under the GNU Lesser General Public License Version 3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the license, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this software.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import annotations

import os
import uuid
import typing as T
from pathlib import Path

import tomlkit as toml

from .unit import EDLUnit, EDLError
from .dataset import EDLDataset


class EDLGroup(EDLUnit):
    """
    An EDL Group
    """

    def __init__(self, name: str | None = None):
        """
        Create a new EDL group.

        If the group has no name and path set, it can not be saved
        to disk.

        Parameters
        ----------
        name
            Name of this group, or None
        """
        EDLUnit.__init__(self, name)
        self._children: list[EDLUnit] = []

    @property
    def children(self) -> list[EDLUnit]:
        return self._children

    @property
    def root_path(self) -> Path | None:
        return self._root_path

    @root_path.setter
    def root_path(self, path: os.PathLike[str]) -> None:
        self._root_path = Path(path)
        for c in self._children:
            c.root_path = self.path

    @property
    def collection_id(self) -> uuid.UUID:
        return self._collection_id

    @collection_id.setter
    def collection_id(self, v: uuid.UUID) -> None:
        self._collection_id = v
        for c in self._children:
            c.collection_id = self._collection_id

    def change_name(self, new_name: str) -> None:
        EDLUnit.change_name(self, new_name)
        for c in self._children:
            c.root_path = self.path

    def add_child(self, child: EDLUnit) -> None:
        if not isinstance(child, EDLUnit):
            raise ValueError('Can only have EDL units as children.')
        if not child.name:
            raise ValueError('Child unit must have a name.')
        old_path = None
        if child.root_path:
            old_path = child.path
        child._parent = self
        child.root_path = self.path
        child.collection_id = self.collection_id

        if old_path and old_path.is_dir():
            old_path.rename(child.path)
        self._children.append(child)

    @property
    def datasets(self) -> T.Iterator[EDLDataset]:
        for child in self._children:
            if isinstance(child, EDLDataset):
                yield child

    @property
    def groups(self) -> T.Iterator[EDLGroup]:
        for child in self._children:
            if isinstance(child, EDLGroup):
                yield child

    def group_by_name(self, name: str, *, create: bool = False) -> EDLGroup | None:
        group: EDLGroup | None
        for group in self.groups:
            if group.name == name:
                return group

        group = None
        if create:
            group = EDLGroup(name)
            self.add_child(group)
            group.save()

        return group

    def dataset_by_name(self, name: str, *, create: bool = False) -> EDLDataset | None:
        dset: EDLDataset | None
        for dset in self.datasets:
            if dset.name == name:
                return dset

        dset = None
        if create:
            dset = EDLDataset(name)
            self.add_child(dset)
            dset.save()

        return dset

    def save(self) -> None:
        if not self.path:
            raise ValueError('No path set for EDL group "{}"'.format(self.name))
        self.path.mkdir(parents=True, exist_ok=True)

        mf = self._make_manifest_dict()
        self._save_metadata(mf, self.attributes)
        for child in self._children:
            child.save()

    def load(self, path: os.PathLike[str], mf: T.MutableMapping[str, T.Any] | None = None) -> None:
        if not mf:
            mf = {}
        EDLUnit.load(self, path, mf)

        for unit_path in self.path.iterdir():
            if not unit_path.is_dir():
                continue
            mf_path = unit_path / 'manifest.toml'
            if not mf_path.is_file():
                continue

            with open(mf_path, 'r', encoding='utf-8') as f:
                mf = toml.load(f)

            unit_type = mf.get('type')
            unit: EDLGroup | EDLDataset
            if unit_type == 'group':
                unit = EDLGroup()
            elif unit_type == 'dataset':
                unit = EDLDataset()
            else:
                raise EDLError(
                    'EDL unit type "{}" is unknown, data can not be loaded.'.format(unit_type)
                )
            unit.load(unit_path, mf)
            self.add_child(unit)
