import os
import sys
from shutil import rmtree
from zipfile import ZipFile

from ..parameters import ZIP_OPTIONS
from ..core.helpers import console, splitModRef

GH_BASE = os.path.expanduser(f'~/github')
DW_BASE = os.path.expanduser(f'~/Downloads')
TEMP = '_temp'
RELATIVE = 'tf'

HELP = '''
USAGE

text-fabric-zip --help

text-fabric-zip {org}/{repo}/{relative}

EFFECT

Zips text-fabric data from your local github repository into
a release file, ready to be attached to a github release.

Your repo must sit in ~/github/{org}/{repo}.

Your TF data is assumed to sit in the toplevel tf directory of your repo.
But if it is somewhere else, you can pass relative, e.g phrases/heads/tf

It is assumed that your tf directory contains subdirectories according to
the versions of the main datasource.
The actual .tf files are in those version directories.

Each of these version directories will be zipped into a separate file.

The resulting zip files end up in ~/Downloads/{org}-release/{repo}
and the are named {relative}-{version}.zip
(where the / in relative have been replaced by -)
'''

EXCLUDE = {'.DS_Store'}


def zipData(org, repo, relative=RELATIVE, tf=True, keep=False):
  console(f'Create release data for {org}/{repo}/{relative}')
  sourceBase = f'{GH_BASE}/{org}'
  destBase = f'{DW_BASE}/{org}-release'
  sourceDir = f'{sourceBase}/{repo}/{relative}'
  destDir = f'{destBase}/{repo}'
  dataFiles = {}

  if not keep:
    if os.path.exists(destDir):
      rmtree(destDir)
  os.makedirs(destDir, exist_ok=True)
  relativeDest = relative.replace('/', '-')

  if tf:
    if not os.path.exists(sourceDir):
      return
    with os.scandir(sourceDir) as sd:
      versionEntries = [
          (sourceDir, e.name)
          for e in sd
          if e.is_dir()
      ]
    if versionEntries:
      console(f'Found {len(versionEntries)} versions')
    else:
      versionEntries.append((sourceDir, ''))
      console(f'Found unversioned features')
    for (versionDir, version) in versionEntries:
      if version == TEMP:
        continue
      versionRep = f'/{version}' if version else ''
      versionRep2 = f'{version}/' if version else ''
      versionRep3 = f'-{version}' if version else ''
      tfDir = f'{versionDir}{versionRep}'
      with os.scandir(tfDir) as sd:
        for e in sd:
          if not e.is_file():
            continue
          featureFile = e.name
          if featureFile in EXCLUDE:
            continue
          if not featureFile.endswith('.tf'):
            console(f'WARNING: non feature file "{versionRep2}{featureFile}"', error=True)
            continue
          dataFiles.setdefault(version, set()).add(featureFile)

    console(f'zip files end up in {destDir}')
    for (version, features) in sorted(dataFiles.items()):
      item = f'{org}/{repo}'
      versionRep = f'/{version}' if version else ''
      versionRep3 = f'-{version}' if version else ''
      target = f'{relativeDest}{versionRep3}.zip'
      console(f'zipping {item:<25} {version:>4} with {len(features):>3} features ==> {target}')
      with ZipFile(
          f'{destDir}/{target}',
          'w',
          **ZIP_OPTIONS,
      ) as zipFile:
        for featureFile in sorted(features):
          zipFile.write(
              f'{sourceDir}{versionRep}/{featureFile}',
              arcname=featureFile,
          )
  else:

    def collectFiles(base, path, results):
      thisPath = f'{base}/{path}' if path else base
      internalBase = f'{relative}/{path}' if path else relative
      with os.scanDir(thisPath) as sd:
        for e in sd:
          name = e.name
          if name in EXCLUDE:
            continue
          if e.is_file():
            results.append((f'{internalBase}/{name}', f'{base}/{path}/{name}'))
          elif e.is_dir():
            collectFiles(base, f'{path}/{name}', results)

    results = []
    collectFiles(sourceDir, '', results)
    if not relativeDest:
      relativeDest = '-'
    console(f'zipping {org}/{repo}/{relative} with {len(results)} files')
    console(f'zip file is {destDir}/{relativeDest}.zip')
    with ZipFile(
        f'{destDir}/{relativeDest}.zip',
        'w',
        **ZIP_OPTIONS,
    ) as zipFile:
      for (internalPath, path) in sorted(results):
        zipFile.write(
            path,
            arcname=internalPath,
        )


def main(cargs=sys.argv):
  if len(cargs) != 2 and any(arg in {'--help', '-help', '-h', '?', '-?'} for arg in cargs):
    console(HELP)
    return

  moduleRef = cargs[1]

  parts = splitModRef(moduleRef)
  if not parts:
    console(HELP)
    return

  (org, repo, relative, checkout) = parts

  tf = (
      relative.endswith('tf') or
      '/tf/' in relative
  )
  sys.stdout.write(f'{tf}\n')

  zipData(org, repo, relative=relative, tf=tf)


if __name__ == "__main__":
  main()

import os
import sys
from shutil import rmtree
from zipfile import ZipFile

from ..parameters import ZIP_OPTIONS
from ..core.helpers import console, splitModRef

GH_BASE = os.path.expanduser(f'~/github')
DW_BASE = os.path.expanduser(f'~/Downloads')
TEMP = '_temp'
RELATIVE = 'tf'

HELP = '''
USAGE

text-fabric-zip --help

text-fabric-zip {org}/{repo}/{relative}

EFFECT

Zips text-fabric data from your local github repository into
a release file, ready to be attached to a github release.

Your repo must sit in ~/github/{org}/{repo}.

Your TF data is assumed to sit in the toplevel tf directory of your repo.
But if it is somewhere else, you can pass relative, e.g phrases/heads/tf

It is assumed that your tf directory contains subdirectories according to
the versions of the main datasource.
The actual .tf files are in those version directories.

Each of these version directories will be zipped into a separate file.

The resulting zip files end up in ~/Downloads/{org}-release/{repo}
and the are named {relative}-{version}.zip
(where the / in relative have been replaced by -)
'''

EXCLUDE = {'.DS_Store'}


def zipData(org, repo, relative=RELATIVE, tf=True, keep=False):
  console(f'Create release data for {org}/{repo}/{relative}')
  sourceBase = f'{GH_BASE}/{org}'
  destBase = f'{DW_BASE}/{org}-release'
  sourceDir = f'{sourceBase}/{repo}/{relative}'
  destDir = f'{destBase}/{repo}'
  dataFiles = {}

  if not keep:
    if os.path.exists(destDir):
      rmtree(destDir)
  os.makedirs(destDir, exist_ok=True)
  relativeDest = relative.replace('/', '-')

  if tf:
    if not os.path.exists(sourceDir):
      return
    with os.scandir(sourceDir) as sd:
      versionEntries = [
          (sourceDir, e.name)
          for e in sd
          if e.is_dir()
      ]
    if versionEntries:
      console(f'Found {len(versionEntries)} versions')
    else:
      versionEntries.append((sourceDir, ''))
      console(f'Found unversioned features')
    for (versionDir, version) in versionEntries:
      if version == TEMP:
        continue
      versionRep = f'/{version}' if version else ''
      versionRep2 = f'{version}/' if version else ''
      versionRep3 = f'-{version}' if version else ''
      tfDir = f'{versionDir}{versionRep}'
      with os.scandir(tfDir) as sd:
        for e in sd:
          if not e.is_file():
            continue
          featureFile = e.name
          if featureFile in EXCLUDE:
            continue
          if not featureFile.endswith('.tf'):
            console(f'WARNING: non feature file "{versionRep2}{featureFile}"', error=True)
            continue
          dataFiles.setdefault(version, set()).add(featureFile)

    console(f'zip files end up in {destDir}')
    for (version, features) in sorted(dataFiles.items()):
      item = f'{org}/{repo}'
      versionRep = f'/{version}' if version else ''
      versionRep3 = f'-{version}' if version else ''
      target = f'{relativeDest}{versionRep3}.zip'
      console(f'zipping {item:<25} {version:>4} with {len(features):>3} features ==> {target}')
      with ZipFile(
          f'{destDir}/{target}',
          'w',
          **ZIP_OPTIONS,
      ) as zipFile:
        for featureFile in sorted(features):
          zipFile.write(
              f'{sourceDir}{versionRep}/{featureFile}',
              arcname=featureFile,
          )
  else:

    def collectFiles(base, path, results):
      thisPath = f'{base}/{path}' if path else base
      internalBase = f'{relative}/{path}' if path else relative
      with os.scanDir(thisPath) as sd:
        for e in sd:
          name = e.name
          if name in EXCLUDE:
            continue
          if e.is_file():
            results.append((f'{internalBase}/{name}', f'{base}/{path}/{name}'))
          elif e.is_dir():
            collectFiles(base, f'{path}/{name}', results)

    results = []
    collectFiles(sourceDir, '', results)
    if not relativeDest:
      relativeDest = '-'
    console(f'zipping {org}/{repo}/{relative} with {len(results)} files')
    console(f'zip file is {destDir}/{relativeDest}.zip')
    with ZipFile(
        f'{destDir}/{relativeDest}.zip',
        'w',
        **ZIP_OPTIONS,
    ) as zipFile:
      for (internalPath, path) in sorted(results):
        zipFile.write(
            path,
            arcname=internalPath,
        )


def main(cargs=sys.argv):
  if len(cargs) != 2 and any(arg in {'--help', '-help', '-h', '?', '-?'} for arg in cargs):
    console(HELP)
    return

  moduleRef = cargs[1]

  parts = splitModRef(moduleRef)
  if not parts:
    console(HELP)
    return

  (org, repo, relative, checkout) = parts

  tf = (
      relative.endswith('tf') or
      '/tf/' in relative
  )
  sys.stdout.write(f'{tf}\n')

  zipData(org, repo, relative=relative, tf=tf)


if __name__ == "__main__":
  main()

USAGE  text-fabric-zip --help  text-fabric-zip {org}/{repo}/{relative}  EFFECT  Zips text-fabric data from your local github repository into a release file, ready to be attached to a github release.  Your repo must sit in ~/github/{org}/{repo}.  Your TF data is assumed to sit in the toplevel tf directory of your repo. But if it is somewhere else, you can pass relative, e.g phrases/heads/tf  It is assumed that your tf directory contains subdirectories according to the versions of the main datasource. The actual .tf files are in those version directories.  Each of these version directories will be zipped into a separate file.  The resulting zip files end up in ~/Downloads/{org}-release/{repo} and the are named {relative}-{version}.zip (where the / in relative have been replaced by -)