#!/usr/bin/python3

from typing import List, Optional
from pydantic import BaseModel
import yaml
import shutil
import zipfile
import os
import sys
from datetime import datetime as dt

# ----

yaml_filename = 'galleries.yaml'
content_dir = "./content"
zip_dir = "./downloads"

# ----

def makeThankYou(gallery:str, date_generated:str):
    return """Thank you for purchasing the "%s" gallery from larsee.com/photography!

By purchasing this product you are granted a license to use the images for any purpose.

This archive was generated: %s. In the future the gallery contents might change.

Don't hesitate to contact me if you have questions or other inquiries. This is my private email: lars@f-w.dk

Sincerely,
Lars Ole Pontoppidan
""" % (gallery, date_generated)

# ----

class Gallery(BaseModel):
    folder_name: str
    title: str
    description: Optional[str] = None
    cover_photo: Optional[str] = None
    photos: List[str]

class Galleries(BaseModel):
    picture_root: str
    galleries: List[Gallery]


def loadGalleries(yaml_file_path: str) -> Galleries:
    with open(yaml_file_path, 'r') as file:
        data = yaml.safe_load(file)
    return Galleries(**data)

def fileTitle(s:str) -> str:
    sp = s.split("/")
    return sp[-1]

class Photo():
    def __init__(self, photo_root:str, source_file:str, prefix:str, index:int):
        sp = source_file.split("/")
        self.photoPath = sp[0]
        self.photoName = sp[1]
        self.destName = prefix + "_%02d.jpg" % index
        self.photoRoot = photo_root
        
    def getDestJpgName(self):
        return self.destName
    
    def getHqFileSource(self):
        return os.path.join(self.photoRoot, self.photoPath, "hq", self.photoName + "_hq.jpg")

    def getRawFilePath(self):
        opt1 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".NEF")
        opt2 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".JPG")
        if os.path.isfile(opt1):
            return opt1
        elif os.path.isfile(opt2):
            return opt2
        else:
            raise Exception("Can't find source file for: " + self.photoName)
    
    def getPp3FilePath(self):
        return self.getRawFilePath() + ".pp3"
   
    def getTifFilePath(self):
        return os.path.join(self.photoRoot, self.photoPath, "converted", self.photoName + ".tif")


class PhotosInGallery():
    def __init__(self, photo_root:str, gallery:Gallery):
        self.photos:List[Photo] = []
        self.cover_photo:Optional[Photo] = None

        for idx, photo in enumerate(gallery.photos, start=1):
            p = Photo(photo_root, photo, gallery.folder_name, idx)
            self.photos.append(p)
            if photo == gallery.cover_photo:
                self.cover_photo = p
    

def makeIndexFile(weight:int, weight_rev:int, gallery:Gallery, photos:PhotosInGallery):
    values = {
        "title" : gallery.title,
        "weight" : weight,
        "menus" : {"main" : {"weight" : weight_rev}},
    }
    if gallery.description is not None:
        values["description"] = gallery.description

    if photos.cover_photo is not None:
        values["featured_image"] = photos.cover_photo.getDestJpgName()

    return "---\n" + yaml.dump(values, default_flow_style=False) + "---\n"

def makeGalleries(yaml_root:Galleries):
    print("Purging old galleries")
    for item in os.listdir(content_dir):
        item_path = os.path.join(content_dir, item)
        if os.path.isdir(item_path):
            print(f"  deleting folder: {item_path}")
            shutil.rmtree(item_path)

    print("Setting up galleries")
    for idx, gallery in enumerate(yaml_root.galleries):
        path = os.path.join(content_dir, gallery.folder_name)
        weight = len(yaml_root.galleries) - idx
        print("  making dir: " + path)
        os.makedirs(path, exist_ok=True)

        photos = PhotosInGallery(yaml_root.picture_root, gallery)

        index = makeIndexFile(weight, idx + 1, gallery, photos)
        with open(os.path.join(path, "index.md"), "w") as f:
            f.write(index)

        # Link in the pictures
        for photo in photos.photos:
            #os.symlink(photo.getHqFileSource(), os.path.join(path, photo.getSimpleJpgName()))
            shutil.copyfile(photo.getHqFileSource(), os.path.join(path, photo.getDestJpgName()))

def makeZipDownloads(yaml_root:Galleries):
    
    if os.path.isdir(zip_dir):
        print("Purging old downloads")
        shutil.rmtree(zip_dir)
    
    os.makedirs(zip_dir, exist_ok=True)

    # Get the current date and time
    dt_now = dt.now()

    print("Making download zips, archive date: " + dt_now.strftime("%B %d, %Y"))

    for gallery in yaml_root.galleries:
        photos = PhotosInGallery(yaml_root.picture_root, gallery)

        # Create a ZIP file for the gallery
        zip_path = os.path.join(zip_dir, "Gallery %s.zip" % gallery.folder_name)
        print("  making zip: " + zip_path)

        #gallery_folder = "%s_%s" % (gallery.folder_name, dt_now.strftime("%b_%d_%Y"))
        gallery_folder = gallery.folder_name

        with zipfile.ZipFile(zip_path, 'w') as myzip:
            def addToZip(path:str, sub_folder:Optional[str] = None):
                if sub_folder is None:
                    myzip.write(path, os.path.join(gallery_folder, os.path.basename(path)))
                else:
                    myzip.write(path, os.path.join(gallery_folder, sub_folder, os.path.basename(path)))

            for photo in photos.photos:
                addToZip(photo.getRawFilePath())
                addToZip(photo.getPp3FilePath())
                addToZip(photo.getTifFilePath(), "converted")
        
            myzip.writestr('Thank you.txt', makeThankYou(gallery.title, dt_now.strftime("%B %d, %Y")))

def main(galleries:bool, zips:bool):
    print("Loading " + yaml_filename)
    yaml_root = loadGalleries(yaml_filename)

    if galleries:
        makeGalleries(yaml_root)
    if zips:
        makeZipDownloads(yaml_root)

def usage():
    print("""
Usage:
    make_galleries OPTIONS
          
Options:
    -g     Make galleries
    -z     Make download zips
""")
    
if __name__ == "__main__":
    zips = "-z" in sys.argv
    galleries = "-g" in sys.argv

    if zips == False and galleries == False:
        usage()
    else:
        main(galleries, zips)
