# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import time
import looker_sdk

from google.cloud import storage
from looker_sdk import models40 as models

# Load environment variables
LOOKER_API_URL = os.getenv("LOOKERSDK_BASE_URL")
LOOKER_CLIENT_ID = os.getenv("LOOKERSDK_CLIENT_ID")
LOOKER_CLIENT_SECRET = os.getenv("LOOKERSDK_CLIENT_SECRET")
TARGET_BUCKET = os.getenv("GCS_BUCKET")

# List of Pairs (Target folder name, Look IDs to download)
LOOKS_TO_DOWNLOAD = [
    ("30", ["18", "50", "92", "49", "91"]),    # BigQueryIO_Read
    ("31", ["19", "52", "88", "51", "87"]),    # BigQueryIO_Write
    ("32", ["20", "60", "104", "59", "103"]),  # BigTableIO_Read
    ("33", ["21", "70", "116", "69", "115"]),  # BigTableIO_Write
    ("34", ["22", "56", "96", "55", "95"]),    # TextIO_Read
    ("35", ["23", "64", "110", "63", "109"]),  # TextIO_Write
    ("75", ["258", "259", "260", "261", "262"]),  # TensorFlow MNIST
    ("76", ["233", "234", "235", "236", "237"]),  # PyTorch BERT base uncased
    ("77", ["238", "239", "240", "241", "242"]),  # PyTorch BERT large uncased
    ("78", ["243", "244", "245", "246", "247"]),  # PyTorch Resnet 101
    ("79", ["248", "249", "250", "251", "252"]),  # PyTorch Resnet 152
    ("80", ["253", "254", "255", "256", "257"]),  # PyTorch Resnet 152 Tesla T4
    ("82", ["263", "264", "265", "266", "267"]),  # PyTorch Sentiment Streaming DistilBERT base uncased
    ("85", ["268", "269", "270", "271", "272"]),  # PyTorch Sentiment Batch DistilBERT base uncased
    ("86", ["284", "285", "286", "287", "288"]),  # VLLM Batch Gemma
    ("96", ["270", "304", "305", "353", "354"]),   # Table Row Inference Sklearn Batch
    ("106", ["355", "356", "357", "358", "359"])   # Table Row Inference Sklearn Streaming
]

def get_look(id: str) -> models.Look:
    look = next(iter(sdk.search_looks(id=id)), None)
    if not look:
        raise Exception(f"look '{id}' was not found")
    print(f"Found look with public_slug = {look.public_slug}")
    return look


def download_look(look: models.Look):
    """Download specified look as png/jpg"""
    task = sdk.create_look_render_task(look.id, "png", 810, 526,)

    if not (task and task.id):
        raise Exception(
            f"Could not create a render task for '{look.title}'"
        )

    # poll the render task until it completes
    elapsed = 0.0
    delay = 20
    retries = 0
    max_retries = 20
    while retries < max_retries:
        poll = sdk.render_task(task.id)
        if poll.status == "failure":
            print(poll)
            raise Exception(f"Render failed for '{look.title}'")
        elif poll.status == "success":
            break
        time.sleep(delay)
        elapsed += delay
        retries += 1
        print(f"Retry {retries}/{max_retries}: Render task still in progress...")

    if retries >= max_retries:
        raise TimeoutError(f"Render task did not complete within {elapsed} seconds (max retries: {max_retries})")

    print(f"Render task completed in {elapsed} seconds")

    return sdk.render_task_results(task.id)


def upload_to_gcs(bucket_name, destination_blob_name, content):
    """Upload content to GCS bucket."""
    client = storage.Client()
    bucket = client.bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)

    # Upload content, overwriting if it exists
    blob.upload_from_string(content, content_type="image/png")
    print(f"Uploaded {destination_blob_name} to {bucket_name}.")


sdk = looker_sdk.init40()


def main():
    failed_looks = []

    for folder, look_ids in LOOKS_TO_DOWNLOAD:
        for look_id in look_ids:
            try:
                if look_id:
                    look = get_look(look_id)
                    content = download_look(look)
                    if content:
                        upload_to_gcs(TARGET_BUCKET, f"{folder}/{look.public_slug}.png", content)
                    else:
                        print(f"No content for look {look_id}")
                        failed_looks.append(look_id)
            except Exception as e:
                print(f"Error processing look {look_id}: {e}")
                failed_looks.append(look_id)

    if failed_looks:
        raise RuntimeError(f"Job failed due to errors in looks: {failed_looks}")


if __name__ == "__main__":
    main()
