#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Part of the PsychoPy library
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2022 Open Science Tools Ltd.
# Distributed under the terms of the GNU General Public License (GPL).
import io
import sys
import tempfile
import time
import os
import traceback
from pathlib import Path

import gitlab
import requests
from .functions import (setLocalPath, showCommitDialog, logInPavlovia,
                        noGitWarning)
from psychopy.localization import _translate
from psychopy.projects import pavlovia
from psychopy import logging

from psychopy.app.pavlovia_ui import sync, functions

import wx
from wx.lib import scrolledpanel as scrlpanel

from .. import utils
from ...projects.pavlovia import PavloviaProject

try:
    import wx.lib.agw.hyperlink as wxhl  # 4.0+
except ImportError:
    import wx.lib.hyperlink as wxhl  # <3.0.2

_starred = u"\u2605"
_unstarred = u"\u2606"


class ProjectEditor(wx.Dialog):
    def __init__(self, parent=None, id=wx.ID_ANY, project=None, localRoot="",
                 *args, **kwargs):

        wx.Dialog.__init__(self, parent, id,
                           *args, **kwargs)
        panel = wx.Panel(self, wx.ID_ANY, style=wx.TAB_TRAVERSAL)
        # when a project is successfully created these will be populated
        if hasattr(parent, 'filename'):
            self.filename = parent.filename
        else:
            self.filename = None
        self.project = project  # type: pavlovia.PavloviaProject
        self.projInfo = None
        self.parent = parent

        if project:
            # edit existing project
            self.isNew = False
            if project.localRoot and not localRoot:
                localRoot = project.localRoot
        else:
            self.isNew = True

        # create the controls
        nameLabel = wx.StaticText(panel, -1, _translate("Name:"))
        self.nameBox = wx.TextCtrl(panel, -1, size=(400, -1))
        # Path can contain only letters, digits, '_', '-' and '.'.
        # Cannot start with '-', end in '.git' or end in '.atom']
        pavSession = pavlovia.getCurrentSession()

        try:
            username = pavSession.user.username
        except AttributeError as e:
            raise pavlovia.NoUserError("{}: Tried to create project with no user logged in.".format(e))

        gpChoices = [username]
        gpChoices.extend(pavSession.listUserGroups())
        groupLabel = wx.StaticText(panel, -1, _translate("Group/owner:"))
        self.groupBox = wx.Choice(panel, -1, size=(400, -1),
                                  choices=gpChoices)

        descrLabel = wx.StaticText(panel, -1, _translate("Description:"))
        self.descrBox = wx.TextCtrl(panel, -1, size=(400, 200),
                                    style=wx.TE_MULTILINE | wx.SUNKEN_BORDER)

        localLabel = wx.StaticText(panel, -1, _translate("Local folder:"))
        self.localBox = wx.TextCtrl(panel, -1, size=(400, -1),
                                    value=localRoot)
        self.btnLocalBrowse = wx.Button(panel, wx.ID_ANY, _translate("Browse..."))
        self.btnLocalBrowse.Bind(wx.EVT_BUTTON, self.onBrowseLocal)
        localPathSizer = wx.BoxSizer(wx.HORIZONTAL)
        localPathSizer.Add(self.localBox)
        localPathSizer.Add(self.btnLocalBrowse)

        tagsLabel = wx.StaticText(panel, -1,
                                  _translate("Tags (comma separated):"))
        self.tagsBox = wx.TextCtrl(panel, -1, size=(400, 100),
                                   value="PsychoPy, Builder, Coder",
                                   style=wx.TE_MULTILINE | wx.SUNKEN_BORDER)
        publicLabel = wx.StaticText(panel, -1, _translate("Public:"))
        self.publicBox = wx.CheckBox(panel, -1)

        # buttons
        if self.isNew:
            buttonMsg = _translate("Create project on Pavlovia")
        else:
            buttonMsg = _translate("Submit changes to Pavlovia")
        updateBtn = wx.Button(panel, -1, buttonMsg)
        updateBtn.Bind(wx.EVT_BUTTON, self.submitChanges)
        cancelBtn = wx.Button(panel, -1, _translate("Cancel"))
        cancelBtn.Bind(wx.EVT_BUTTON, self.onCancel)
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        if sys.platform == "win32":
            btns = [updateBtn, cancelBtn]
        else:
            btns = [cancelBtn, updateBtn]
        btnSizer.AddMany(btns)

        # do layout
        fieldsSizer = wx.FlexGridSizer(cols=2, rows=6, vgap=5, hgap=5)
        fieldsSizer.AddMany([(nameLabel, 0, wx.ALIGN_RIGHT), self.nameBox,
                             (groupLabel, 0, wx.ALIGN_RIGHT), self.groupBox,
                             (localLabel, 0, wx.ALIGN_RIGHT), localPathSizer,
                             (descrLabel, 0, wx.ALIGN_RIGHT), self.descrBox,
                             (tagsLabel, 0, wx.ALIGN_RIGHT), self.tagsBox,
                             (publicLabel, 0, wx.ALIGN_RIGHT), self.publicBox])

        border = wx.BoxSizer(wx.VERTICAL)
        border.Add(fieldsSizer, 0, wx.ALL, 5)
        border.Add(btnSizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
        panel.SetSizerAndFit(border)
        self.Fit()

    def onCancel(self, evt=None):
        self.EndModal(wx.ID_CANCEL)

    def submitChanges(self, evt=None):
        session = pavlovia.getCurrentSession()
        if not session.user:
            user = logInPavlovia(parent=self.parent)
        if not session.user:
            return
        # get current values
        name = self.nameBox.GetValue()
        namespace = self.groupBox.GetStringSelection()
        descr = self.descrBox.GetValue()
        visibility = self.publicBox.GetValue()
        # tags need splitting and then
        tagsList = self.tagsBox.GetValue().split(',')
        tags = [thisTag.strip() for thisTag in tagsList]
        localRoot = self.localBox.GetValue()
        if not localRoot:
            localRoot = setLocalPath(self.parent, project=None, path="")

        # then create/update
        if self.isNew:
            project = session.createProject(name=name,
                                            description=descr,
                                            tags=tags,
                                            visibility=visibility,
                                            localRoot=localRoot,
                                            namespace=namespace)
            self.project = project
            self.project._newRemote = True
        else:  # we're changing metadata of an existing project. Don't sync
            self.project.pavlovia.name = name
            self.project.pavlovia.description = descr
            self.project.tags = tags
            self.project.visibility = visibility
    
        self.project.localRoot = localRoot
            self.project.save()  # pushes changed metadata to gitlab
            self.project._newRemote = False

        self.EndModal(wx.ID_OK)
        pavlovia.knownProjects.save()
        self.project.getRepo(forceRefresh=True)
        self.parent.project = self.project

    def onBrowseLocal
(self, evt=None):
        newPath = setLocalPath(self, path=self.filename)
        if newPath:
            self.localBox.SetLabel(newPath)
            self.Layout()
            if self.project:
                self.project.localRoot = newPath
        self.Raise()


class DetailsPanel(wx.Panel):

    class StarBtn(wx.Button):
        def __init__(self, parent, iconCache, value=False):
            wx.Button.__init__(self, parent, label=_translate("Star"))
            # Setup icons
            self.icons = {
                True: iconCache.getBitmap(name="starred", size=16),
                False: iconCache.getBitmap(name="unstarred", size=16),
            }
            self.SetBitmapDisabled(self.icons[False])  # Always appear empty when disabled
            # Set start value
            self.value = value

        @property
        def value(self):
            return self._value

        @value.setter
        def value(self, value):
            # Store value
            self._value = bool(value)
            # Change icon
            self.SetBitmap(self.icons[self._value])
            self.SetBitmapCurrent(self.icons[self._val