from flask import Flask, render_template, request, redirect, url_for, jsonify
import json
import requests
import logging
import os
import traceback
import time
import sys

app = Flask(__name__)

# Determine logging level
if '--debug' in sys.argv:
    logging_level = logging.DEBUG
else:
    logging_level = logging.INFO

# Setup logging to file
logging.basicConfig(filename='log.log', level=logging_level, format='%(asctime)s %(levelname)s:%(message)s')

# File paths
ASSORT_FILE_PATH = 'assort.json'
QUEST_ASSORT_FILE_PATH = 'questassort.json'
CACHE_FILE_PATH = 'item_cache.json'
RUBLE_TPL_ID = '5449016a4bdc2d6f028b456f'

# Load assort data
try:
    with open(ASSORT_FILE_PATH) as f:
        assort_data = json.load(f)
        logging.info("Assort data loaded successfully")
except Exception as e:
    logging.error(f"Error loading assort data: {e}")
    logging.error(traceback.format_exc())

try:
    with open(QUEST_ASSORT_FILE_PATH) as f:
        quest_assort_data = json.load(f)
        logging.info("Quest assort data loaded successfully")
except json.JSONDecodeError as e:
    logging.error(f"Error loading quest assort data (malformed JSON): {e}")
    logging.error(traceback.format_exc())
    quest_assort_data = {}
except Exception as e:
    logging.error(f"Error loading quest assort data: {e}")
    logging.error(traceback.format_exc())
    quest_assort_data = {}

# Load cache or initialize an empty dictionary
def load_item_cache():
    global item_cache
    if os.path.exists(CACHE_FILE_PATH):
        try:
            with open(CACHE_FILE_PATH) as f:
                item_cache = json.load(f)
                logging.info("Item cache loaded successfully")
        except Exception as e:
            logging.error(f"Error loading item cache: {e}")
            logging.error(traceback.format_exc())
            item_cache = {}
    else:
        item_cache = {}
        logging.info("Initialized empty item cache")

load_item_cache()

# Tarkov.dev API URL
TARKOV_API_URL = "https://api.tarkov.dev/graphql"

def get_ruble_image():
    return get_item_details_cached(RUBLE_TPL_ID)

@app.route('/')
def index():
    if not is_cache_complete():
        return redirect(url_for('build_cache'))

    try:
        items = get_main_items_with_details(assort_data)
        ruble_image = get_ruble_image()
        return render_template('index.html', items=items, ruble_image=ruble_image)
    except Exception as e:
        logging.error(f"Error in index route: {e}")
        logging.error(traceback.format_exc())
        return "Error loading items", 500

def get_main_items_with_details(assort_data):
    items = []
    for item in assort_data['items']:
        if item['parentId'] == 'hideout':
            item_copy = item.copy()  # Create a copy of the item to avoid modifying the original
            item_copy['details'] = get_item_details_cached(item_copy['_tpl'])
            item_copy['parts'] = get_item_parts_with_details(item_copy['_id'], assort_data)
            item_copy['barter_scheme'] = get_barter_scheme_with_details(item_copy['_id'], assort_data)
            item_copy['quest_requirement'] = get_quest_requirement(item_copy['_id'])
            item_copy['offer_name'] = item_copy['_id']  # Add offer name
            items.append(item_copy)
    logging.info(f"Main items with details: {items}")
    return items

def get_item_details_cached(tpl):
    if tpl in item_cache:
        logging.info(f"Cache hit for tpl {tpl}")
        return item_cache[tpl]
    else:
        logging.info(f"Cache miss for tpl {tpl}, fetching from API")
        item_details = get_items_details([tpl])
        if tpl in item_details:
            item_cache[tpl] = item_details[tpl]
            save_item_cache()
        return item_details.get(tpl, {})

def get_items_details(tpls):
    queries = "\n".join([
        f'item{index}: item(id: "{tpl}") {{ id name shortName description basePrice image512pxLink wikiLink }}'
        for index, tpl in enumerate(tpls)
    ])
    query = f"{{ {queries} }}"
    try:
        response = requests.post(TARKOV_API_URL, json={'query': query})
        data = response.json()
        logging.info(f"Item details for tpls {tpls}: {data}")
        return {tpl: data['data'][f'item{index}'] for index, tpl in enumerate(tpls)}
    except Exception as e:
        logging.error(f"Error fetching item details for tpls {tpls}: {e}")
        logging.error(traceback.format_exc())
        return {}

def get_item_parts_with_details(parent_id, assort_data):
    parts = []
    def fetch_parts(parent_id):
        sub_parts = []
        for item in assort_data['items']:
            if item['parentId'] == parent_id:
                part_copy = item.copy()  # Create a copy of the part to avoid modifying the original
                part_copy['details'] = get_item_details_cached(part_copy['_tpl'])
                part_copy['parts'] = fetch_parts(part_copy['_id'])  # Fetch sub-parts recursively
                sub_parts.append(part_copy)
        return sub_parts
    parts = fetch_parts(parent_id)
    logging.info(f"Parts for parent_id {parent_id}: {parts}")
    return parts

def get_barter_scheme_with_details(item_id, assort_data):
    barter_scheme = []
    if 'barter_scheme' in assort_data:
        for scheme in assort_data['barter_scheme'].get(item_id, []):
            scheme_details = []
            for req in scheme:
                req_copy = req.copy()  # Create a copy of the req to avoid modifying the original
                req_details = get_item_details_cached(req_copy['_tpl'])
                req_copy['details'] = req_details
                scheme_details.append(req_copy)
            barter_scheme.append(scheme_details)
    logging.info(f"Barter scheme for item_id {item_id}: {barter_scheme}")
    return barter_scheme

def get_quest_requirement(item_id):
    for quest_type, quests in quest_assort_data.items():
        if item_id in quests:
            return {
                "type": quest_type,
                "quest": quests[item_id]
            }
    return None

def get_all_item_ids(assort_data):
    ids = set()
    for item in assort_data['items']:
        ids.add(item['_tpl'])
        for part in item.get('parts', []):
            ids.add(part['_tpl'])
    for schemes in assort_data.get('barter_scheme', {}).values():
        for scheme in schemes:
            for req in scheme:
                ids.add(req['_tpl'])
    return list(ids)

def is_cache_complete():
    item_ids = get_all_item_ids(assort_data)
    for item_id in item_ids:
        if item_id not in item_cache:
            return False
    return True

def build_item_cache():
    try:
        item_ids = get_all_item_ids(assort_data)
        item_details = get_items_details(item_ids)
        for tpl, details in item_details.items():
            item_cache[tpl] = details
        save_item_cache()
        return True
    except Exception as e:
        logging.error(f"Error building item cache: {e}")
        logging.error(traceback.format_exc())
        return False

@app.route('/edit/<item_id>', methods=['GET', 'POST'])
def edit_item(item_id):
    try:
        if request.method == 'POST':
            # Handle form submission
            new_barter_scheme = []
            tpl_list = request.form.getlist('barter_tpl')
            count_list = request.form.getlist('barter_count')
            scheme = []
            for i in range(len(tpl_list)):
                scheme.append({
                    '_tpl': tpl_list[i],
                    'count': int(count_list[i])
                })
            new_barter_scheme.append(scheme)
            update_barter_scheme(item_id, new_barter_scheme)
            return redirect(url_for('index'))

        item = next((item for item in assort_data['items'] if item['_id'] == item_id), None)
        if item:
            item_copy = item.copy()  # Create a copy of the item to avoid modifying the original
            item_copy['details'] = get_item_details_cached(item_copy['_tpl'])
            item_copy['parts'] = get_item_parts_with_details(item_id, assort_data)
            item_copy['barter_scheme'] = get_barter_scheme_with_details(item_id, assort_data)
            item_copy['quest_requirement'] = get_quest_requirement(item_id)
            ruble_image = get_ruble_image()
            return render_template('edit.html', item=item_copy, ruble_image=ruble_image)
        else:
            return "Item not found", 404
    except Exception as e:
        logging.error(f"Error in edit_item route: {e}")
        logging.error(traceback.format_exc())
        return "Error editing item", 500

def update_barter_scheme(item_id, new_barter_scheme):
    try:
        assort_data['barter_scheme'][item_id] = new_barter_scheme
        save_assort_data()
    except Exception as e:
        logging.error(f"Error updating barter scheme for item {item_id}: {e}")
        logging.error(traceback.format_exc())

def save_assort_data():
    try:
        # Deep copy the assort data and remove 'details' key before saving
        cleaned_assort_data = json.loads(json.dumps(assort_data))  # Deep copy

        # Clean items
        for item in cleaned_assort_data['items']:
            if 'details' in item:
                del item['details']

        # Clean barter_scheme
        for item_id, schemes in cleaned_assort_data.get('barter_scheme', {}).items():
            for scheme in schemes:
                for part in scheme:
                    if 'details' in part:
                        del part['details']
        
        # Backup the existing assort.json
        if not os.path.exists('./bkp'):
            os.makedirs('./bkp')
        backup_file_path = os.path.join('./bkp', f"assort_backup_{int(time.time())}.json")
        if os.path.exists(ASSORT_FILE_PATH):
            os.rename(ASSORT_FILE_PATH, backup_file_path)
            logging.info(f"Backup of assort data created at {backup_file_path}")

        with open(ASSORT_FILE_PATH, 'w') as f:
            json.dump(cleaned_assort_data, f, indent=2)  # Use 2 spaces for indentation
            logging.info("Assort data saved successfully")
    except Exception as e:
        logging.error(f"Error saving assort data: {e}")
        logging.error(traceback.format_exc())

def save_item_cache():
    try:
        with open(CACHE_FILE_PATH, 'w') as f:
            json.dump(item_cache, f, indent=2)  # Use 2 spaces for indentation
            logging.info("Item cache saved successfully")
    except Exception as e:
        logging.error(f"Error saving item cache: {e}")
        logging.error(traceback.format_exc())

@app.route('/item_image/<tpl>')
def item_image(tpl):
    details = get_item_details_cached(tpl)
    return jsonify({'image512pxLink': details.get('image512pxLink', ''), 'name': details.get('name', '')})

@app.route('/search_items', methods=['GET'])
def search_items():
    query = request.args.get('query', '')
    if not query:
        return jsonify([])

    search_query = f'''
    {{
      items(name: "{query}") {{
        id
        name
        gridImageLink
      }}
    }}
    '''
    
    try:
        response = requests.post(TARKOV_API_URL, json={'query': search_query})
        data = response.json()
        items = data['data'].get('items', [])
        return jsonify(items)
    except Exception as e:
        logging.error(f"Error searching for items with query '{query}': {e}")
        logging.error(traceback.format_exc())
        return jsonify([]), 500

@app.route('/build_cache', methods=['GET'])
def build_cache():
    return render_template('build_cache.html')

@app.route('/start_build_cache', methods=['POST'])
def start_build_cache():
    success = build_item_cache()
    if success:
        return jsonify({"status": "success"})
    else:
        return jsonify({"status": "error"}), 500

if __name__ == '__main__':
    print("Webapp is hosted at http://127.0.0.1:5000")
    app.run(debug='--debug' in sys.argv)