import os
import markdown
import re
from jinja2 import Environment, FileSystemLoader
import yaml
import time
import json

class Website:
    def __init__(self, template_dir, public_dir):
        self.template_dir_root = template_dir
        self.public_dir = public_dir
        self.output_dir_root = 'public/articles'
        self.env = Environment(loader=FileSystemLoader(self.template_dir_root))
        self.pages = []
        self.tags = []
        self.all_images = []
        self.about_meta, self.about_content, self.about_modified_time = self.fetch_page('content', 'about.md')
    
    def build(self):
        self.fetch_pages()
        self.process_page()
        self.fetch_tags()
        self.create_list()
        self.build_about()
        self.fetch_all_images()
        self.create_json('public/json/articles.json')
        
    def fetch_pages(self):
        for page in os.listdir('content/posts'):
            if page.endswith('.md'):
                with open(os.path.join('content/posts', page), 'r', encoding="utf8") as f:
                    content = f.read()
                    file_desc = f.fileno()
                    file_status = os.fstat(file_desc)
                    parts = content.split('---')
                    metadata = yaml.safe_load(parts[1])
                    md_content = ''.join(parts[2:])
                    md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', md_content)
                    md_content = self.format_content(md_content)
                    html_content = markdown.markdown(md_content)
                    output_filename = os.path.splitext(page)[0] + '.html'
                    new_page = Page(metadata, html_content, output_filename, file_status)
                    self.pages.append(new_page)
               
    def process_page(self):
         template = self.env.get_template('article.html')
         self.check_output_dir()
         for page in self.pages:
             metadata = page.get_metadata()
             filename = page.get_filename()
             html_content = page.get_content()
             html_output = template.render(
                 	title=metadata.get('title', ''), 
					year=metadata.get('year', ''),  # Assuming year is a string
					date=metadata.get('date', ''),  # Assuming date is a string
					tags=metadata.get('tags', []),
					image=metadata.get('image', ''),  # Assuming image is a string
					showcase=metadata.get('showcase', []),
					credits=metadata.get('credits', []),  # Assuming credits is a string
					modified_time=page.get_modified_time_readable(),
                 content=html_content)
             with open(os.path.join(self.output_dir_root, filename), 'w', encoding='utf8') as output_file:
                        output_file.write(html_output)
     
    def check_output_dir(self):
        if not os.path.exists(self.output_dir_root):
            os.makedirs(self.output_dir_root)
            
    def fetch_page(self, dir, page):
        for about in os.listdir(dir):
            if about == page:
                with open(os.path.join(dir, about), 'r', encoding='utf8') as f:
                    content = f.read()
                    parts = content.split('---')
                    metadata = yaml.safe_load(parts[1])
                    md_content = ''.join(parts[2:])
                    md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', md_content)
                    html_content = markdown.markdown(md_content)
                    about_modified_time = time.ctime(os.fstat(f.fileno()).st_mtime)
                    return metadata, html_content, about_modified_time
       
    def create_list(self):
        template = self.env.get_template('list.html')
        self.check_output_dir()
        html_output = template.render(
            tags=self.tags,
			pages=self.pages
		)
        with open(os.path.join('public', 'list.html'), 'w', encoding='utf8') as output_file:
            output_file.write(html_output)
       
    def fetch_tags(self):
        for page in self.pages:
            page_tags = page.get_tags()
            for tag in page_tags:
                if tag not in self.tags:
                    self.tags.append(tag)  
      
    def build_about(self):
        template = self.env.get_template('about.html')
        html_output = template.render(
			content=self.about_content,
			socials=self.about_meta,
			modified_time = self.about_modified_time
		)
        with open(os.path.join('public', 'about.html'), 'w', encoding='utf8') as output_file:
                        output_file.write(html_output)
       
    def format_content(self, content):
        # convert all (link)(src) to <a> tags
        content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', content)
        # convert all video links to embedded code
        return content
        
    def fetch_all_images(self):
        dir = 'public/images'
        template = self.env.get_template('gallery.html')
        image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.webp')
        for dirpath, _, filename in os.walk(dir):
            for filename in filename:
                if filename.lower().endswith(image_extensions):
                    relative_path = os.path.relpath(dirpath, dir).replace("\\", "/")
                    image_path = os.path.join('/images', relative_path, filename).replace("\\", "/")
                    if image_path.startswith("/images/."):
                        image_path = image_path.replace("/images/.", "/images")
                    self.all_images.append(image_path)
                    
        html_output = template.render(
			images=self.all_images
		)
        with open(os.path.join('public', 'gallery.html'), 'w', encoding='utf8') as output_file:
                        output_file.write(html_output)
        
    def create_json(self, json_file):
        page_info_list = []
        for page in self.pages:
            page_info = {
				'name': page.get_title(),
				'filename': '/articles/' + page.get_filename(),
				'image': page.get_image()
			}
            page_info_list.append(page_info)
        
        with open(json_file, 'w', encoding='utf8') as f:
            json.dump(page_info_list, f, ensure_ascii=False, indent=4)
            
class Page:
    def __init__(self, metadata, md_content, filename, last_updated):
        self.metadata = metadata
        self.content = md_content
        self.filename = filename
        self.last_updated = last_updated
        self.title = self.metadata['title']
        self.type = self.metadata['type']
        self.year = self.metadata['year']
        self.image_src = self.metadata['image']
        self.tags = self.metadata['tags']
        self.date = self.metadata['date']
        self.showcase = self.metadata.get('showcase', [])
        self.credits = self.metadata.get('credits', {})
        self.references = self.metadata.get('references', [])
        self.isDraft = self.metadata['draft']
        
    def get_metadata(self):
        return self.metadata
    
    def get_content(self):
        return self.content
    
    def get_filename(self):
        return self.filename
    
    def get_title(self):
        return self.title
    
    def get_tags(self):
        return self.tags
    
    def get_year(self):
        return self.year
    
    def get_image(self):
        return self.image_src
    
    def get_references(self):
        return self.references
    
    def get_src(self):
        return os.path.splitext(self.filename)[0]
        
    def display_metadata(self):
        output = f"Title: {self.title}\nYear: {self.year}\nDate: {self.date}\nTags: {self.tags}\nType: {self.type}"
        print(output)
        
    def get_modified_time_readable(self):
        if self.last_updated is not None:
            last_modified_time = self.last_updated.st_mtime
            last_modified_time_readable = time.ctime(last_modified_time)
            return last_modified_time_readable
        return None

def main():
    inst = Website('templates', 'public')
    inst.build()
    
if __name__ == "__main__":
    main()