#!/usr/bin/env python3
"""
Cross-platform Excel generation script using openpyxl.
This version ensures clean Excel files without SharePoint/OneDrive metadata.
"""
import json
import os
import datetime
from pathlib import Path
from dateutil.relativedelta import relativedelta
import openpyxl
from openpyxl.workbook import Workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
import tempfile
import shutil




def create_excel_from_template():
    """
    Create an Excel file from template with all placeholders replaced.
    Uses openpyxl for maximum cross-platform compatibility.
    """
    # Define paths
    script_dir = os.path.dirname(os.path.abspath(__file__))
    config_path = os.path.join(script_dir, 'config.json')
    template_dir = os.path.join(script_dir, 'template')

    # Try to find the template with either naming convention
    possible_templates = [
        'cleaned_template.xlsx',  # Prefer cleaned template
        'Footprints AI for {store_name} - Retail Media Business Case Calculations.xlsx',
        'Footprints AI for store_name - Retail Media Business Case Calculations.xlsx'
    ]

    template_path = None
    for template_name in possible_templates:
        full_path = os.path.join(template_dir, template_name)
        if os.path.exists(full_path):
            template_path = full_path
            print(f"Found template: {template_name}")
            break

    if not template_path:
        print(f"Error: No template found in {template_dir}")
        return False

    output_dir = os.path.join(script_dir, 'output')
    os.makedirs(output_dir, exist_ok=True)

    # Read config.json
    try:
        with open(config_path, 'r') as f:
            config = json.load(f)
            user_data = config.get('user_data', {})
            store_name = user_data.get('store_name', 'Your Store')
            starting_date = user_data.get('starting_date', '')
            duration = user_data.get('duration', 36)

            if not store_name:
                store_name = "Your Store"

            print(f"Processing for store: {store_name}")

            # Calculate years array
            years = calculate_years(starting_date, duration)
            calculated_years = years
            print(f"Years in the period: {years}")
    except Exception as e:
        print(f"Error reading config file: {e}")
        return False

    # Determine year range for filename
    year_range = ""
    if years and len(years) > 0:
        if len(years) == 1:
            year_range = f"{years[0]}"
        else:
            year_range = f"{years[0]}-{years[-1]}"
    else:
        year_range = f"{datetime.datetime.now().year}"

    # Create output filename
    output_filename = f"Footprints AI for {store_name} - Retail Media Business Case Calculations {year_range}.xlsx"
    output_path = os.path.join(output_dir, output_filename)

    try:
        # Load template with data_only=False to preserve formulas
        print("Loading template...")
        wb = openpyxl.load_workbook(template_path, data_only=False, keep_vba=False)


        # Build mapping of placeholder patterns to actual values
        placeholder_patterns = [
            ('{store_name}', store_name),
            ('store_name', store_name)
        ]

        # Step 1: Create sheet name mappings
        print("Processing sheet names...")
        sheet_name_mappings = {}
        sheets_to_rename = []

        for sheet in wb.worksheets:
            old_title = sheet.title
            new_title = old_title

            for placeholder, replacement in placeholder_patterns:
                if placeholder in new_title:
                    new_title = new_title.replace(placeholder, replacement)

            if old_title != new_title:
                sheet_name_mappings[old_title] = new_title
                sheet_name_mappings[f"'{old_title}'"] = f"'{new_title}'"
                sheets_to_rename.append((sheet, new_title))
                print(f"  Will rename: '{old_title}' -> '{new_title}'")

        # Step 2: Update all formulas and values
        print("Updating formulas and cell values...")
        total_updates = 0

        for sheet in wb.worksheets:
            if 'Variables' in sheet.title:
                continue

            updates_in_sheet = 0
            for row in sheet.iter_rows():
                for cell in row:
                    try:
                        # Handle formulas
                        if hasattr(cell, '_value') and isinstance(cell._value, str) and cell._value.startswith('='):
                            original = cell._value
                            updated = original

                            # Update sheet references
                            for old_ref, new_ref in sheet_name_mappings.items():
                                updated = updated.replace(old_ref, new_ref)

                            # Update placeholders
                            for placeholder, replacement in placeholder_patterns:
                                updated = updated.replace(placeholder, replacement)

                            if updated != original:
                                cell._value = updated
                                updates_in_sheet += 1

                        # Handle regular text values
                        elif cell.value and isinstance(cell.value, str):
                            original = cell.value
                            updated = original

                            for placeholder, replacement in placeholder_patterns:
                                updated = updated.replace(placeholder, replacement)

                            if updated != original:
                                cell.value = updated
                                updates_in_sheet += 1
                    except Exception as e:
                        # Skip cells that cause issues
                        continue

            if updates_in_sheet > 0:
                print(f"  {sheet.title}: {updates_in_sheet} updates")
                total_updates += updates_in_sheet

        print(f"Total updates: {total_updates}")

        # Step 3: Rename sheets
        print("Renaming sheets...")
        for sheet, new_title in sheets_to_rename:
            old_title = sheet.title
            sheet.title = new_title
            print(f"  Renamed: '{old_title}' -> '{new_title}'")

            # Hide forecast sheets not in calculated years
            if "Forecast" in new_title:
                try:
                    sheet_year = int(new_title.split()[0])
                    if sheet_year not in calculated_years:
                        sheet.sheet_state = 'hidden'
                        print(f"  Hidden sheet '{new_title}' (year {sheet_year} not in range)")
                except (ValueError, IndexError):
                    pass

        # Step 4: Update Variables sheet
        print("Updating Variables sheet...")
        if 'Variables' in wb.sheetnames:
            update_variables_sheet(wb['Variables'], user_data)

        # Step 5: Save as a clean Excel file
        print(f"Saving clean Excel file to: {output_path}")

        # Create a temporary file first
        with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as tmp:
            tmp_path = tmp.name

        # Save to temporary file
        wb.save(tmp_path)

        # Re-open and save again to ensure clean structure
        wb_clean = openpyxl.load_workbook(tmp_path, data_only=False)
        wb_clean.save(output_path)
        wb_clean.close()

        # Clean up temporary file
        os.unlink(tmp_path)

        print(f"✓ Excel file created successfully: {output_filename}")
        return True

    except Exception as e:
        print(f"Error creating Excel file: {e}")
        import traceback
        traceback.print_exc()
        return False


def update_variables_sheet(sheet, user_data):
    """
    Update the Variables sheet with values from config.json
    """
    cell_mappings = {
        'B2': user_data.get('store_name', ''),
        'B31': user_data.get('starting_date', ''),
        'B32': user_data.get('duration', 36),
        'B37': user_data.get('open_days_per_month', 0),

        # Store types
        'H37': user_data.get('convenience_store_type', {}).get('stores_number', 0),
        'C37': user_data.get('convenience_store_type', {}).get('monthly_transactions', 0),
        'I37': 1 if user_data.get('convenience_store_type', {}).get('has_digital_screens', False) else 0,
        'J37': user_data.get('convenience_store_type', {}).get('screen_count', 0),
        'K37': user_data.get('convenience_store_type', {}).get('screen_percentage', 0),
        'M37': 1 if user_data.get('convenience_store_type', {}).get('has_in_store_radio', False) else 0,
        'N37': user_data.get('convenience_store_type', {}).get('radio_percentage', 0),

        'H38': user_data.get('minimarket_store_type', {}).get('stores_number', 0),
        'C38': user_data.get('minimarket_store_type', {}).get('monthly_transactions', 0),
        'I38': 1 if user_data.get('minimarket_store_type', {}).get('has_digital_screens', False) else 0,
        'J38': user_data.get('minimarket_store_type', {}).get('screen_count', 0),
        'K38': user_data.get('minimarket_store_type', {}).get('screen_percentage', 0),
        'M38': 1 if user_data.get('minimarket_store_type', {}).get('has_in_store_radio', False) else 0,
        'N38': user_data.get('minimarket_store_type', {}).get('radio_percentage', 0),

        'H39': user_data.get('supermarket_store_type', {}).get('stores_number', 0),
        'C39': user_data.get('supermarket_store_type', {}).get('monthly_transactions', 0),
        'I39': 1 if user_data.get('supermarket_store_type', {}).get('has_digital_screens', False) else 0,
        'J39': user_data.get('supermarket_store_type', {}).get('screen_count', 0),
        'K39': user_data.get('supermarket_store_type', {}).get('screen_percentage', 0),
        'M39': 1 if user_data.get('supermarket_store_type', {}).get('has_in_store_radio', False) else 0,
        'N39': user_data.get('supermarket_store_type', {}).get('radio_percentage', 0),

        'H40': user_data.get('hypermarket_store_type', {}).get('stores_number', 0),
        'C40': user_data.get('hypermarket_store_type', {}).get('monthly_transactions', 0),
        'I40': 1 if user_data.get('hypermarket_store_type', {}).get('has_digital_screens', False) else 0,
        'J40': user_data.get('hypermarket_store_type', {}).get('screen_count', 0),
        'K40': user_data.get('hypermarket_store_type', {}).get('screen_percentage', 0),
        'M40': 1 if user_data.get('hypermarket_store_type', {}).get('has_in_store_radio', False) else 0,
        'N40': user_data.get('hypermarket_store_type', {}).get('radio_percentage', 0),

        # Channels
        'B43': user_data.get('website_visitors', 0),
        'B44': user_data.get('app_users', 0),
        'B45': user_data.get('loyalty_users', 0),
        'B49': user_data.get('facebook_followers', 0),
        'B50': user_data.get('instagram_followers', 0),
        'B51': user_data.get('google_views', 0),
        'B52': user_data.get('email_subscribers', 0),
        'B53': user_data.get('sms_users', 0),
        'B54': user_data.get('whatsapp_contacts', 0)
    }

    for cell_ref, value in cell_mappings.items():
        try:
            sheet[cell_ref].value = value
            print(f"  Updated {cell_ref} = {value}")
        except Exception as e:
            print(f"  Warning: Could not update {cell_ref}: {e}")


def calculate_years(starting_date, duration):
    """
    Calculate an array of years that appear in the period.
    """
    default_years = [datetime.datetime.now().year]

    if not starting_date:
        return default_years

    try:
        # Parse date - support multiple formats
        if '/' in str(starting_date):
            day, month, year = map(int, str(starting_date).split('/'))
        elif '.' in str(starting_date):
            day, month, year = map(int, str(starting_date).split('.'))
        elif '-' in str(starting_date):
            # ISO format (yyyy-mm-dd)
            date_parts = str(starting_date).split('-')
            if len(date_parts) == 3:
                year, month, day = map(int, date_parts)
            else:
                return default_years
        else:
            return default_years

        start_date = datetime.datetime(year, month, day)
        end_date = start_date + relativedelta(months=duration-1)

        years_set = set()
        years_set.add(start_date.year)
        years_set.add(end_date.year)

        for y in range(start_date.year + 1, end_date.year):
            years_set.add(y)

        return sorted(list(years_set))

    except Exception as e:
        print(f"Error calculating years: {e}")
        return default_years


if __name__ == "__main__":
    create_excel_from_template()