import json
import os
from io import BytesIO
from random import randint
import random

import requests
from dotenv import load_dotenv
import urllib
from environment import Environment
from exceptions import (MatchingContentNotFoundException,
                        OfferNotFoundForUserException)
from flask import Flask, abort, jsonify, request, send_file
from flask_cors import CORS
from flask_mail import Mail
from services.autopilot import Autopilot
from services.content_evaluator import ContentEvaluator
from services.firebase.firebase_storage_service import FirebaseStorageService
from services.firebase.firestore_service import FirestoreService
from services.instagram.private_instagram_scraper import \
    PrivateInstagramScraper
from services.instagram.public_instagram_scraper import PublicInstagramScraper
from services.integrations.shopify_service import ShopifyService
from services.notifications.email_service import EmailService
from services.notifications.sms_service import SMSService
from services.payments.dots_payment_service import DOTSPaymentService
from services.payments.stripe_service import StripeService
from services.scheduling.scheduling_service import SchedulingService

app = Flask(__name__)
# Enable CORS, which is required for making requests from browsers. Enable headers for all routes.
CORS(app, resources={r"*": {"origins": "*", "allow_headers": "*"}},
     supports_credentials=True, automatic_options=True)

load_dotenv()
API_KEY = os.environ.get("FLASK_API_KEY")

# set up email server details
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USERNAME'] = 'storyitinternalalerts'
app.config['MAIL_PASSWORD'] = os.environ.get(
    "GMAIL_ALERTS_ACCOUNT_APP_PASSWORD")
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False

mail = Mail(app)

# Require API key for all requests


@app.before_request
def require_api_key():
    if request.method == 'OPTIONS':
        return  # Allow CORS preflight requests to pass
    if request.headers.get('Authorization') != API_KEY and request.headers.get('X-Appengine-Cron') != 'true':
        abort(401, 'Invalid API key')


@app.route('/')
def index():
    return 'You have reached the backend.'

# Health check endpoint
# Returns 201 if server is alive and running in prod, otherwise returns 202


@app.route('/heartbeat/')
def heartbeat():
    return jsonify({"status": "alive"}), 202 if Environment.USE_TEST_MODE else 201


# Methods for Instagram
private_instagram_scraper = PrivateInstagramScraper()
public_instagram_scraper = PublicInstagramScraper()


@app.route('/instagram/get-profile/<username>')
def get_instagram_profile(username):
    try:
        profile, status_code = public_instagram_scraper.get_user_profile(
            username)
        if status_code != 200:
            return jsonify({"error": "Error getting user profile"}), status_code
        return jsonify(profile), 200
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route('/instagram/follow-user/<username>')
def follow_instagram_user(username):
    server_name = request.args.get('server_name')
    print(f"attempting to follow user on server {server_name}")
    return private_instagram_scraper.follow_user(username, server_name)

# Methods related to Instagram Stories


@app.route('/verify/schedule-content-verification/', methods=['POST'])
def schedule_content_verification():
    data = request.json
    ig_id = data.get('ig_id')
    required_tagged_username = data.get('required_tagged_username')
    ig_is_private = data.get('ig_is_private')
    username = data.get('username')
    bot_username = data.get('bot_username')
    phone_number = data.get('phone_number')
    offer_id = data.get('offer_id')
    client_id = data.get('client_id')
    location_id = data.get('location_id')
    content_type = data.get('content_type')
    ugc_url = data.get('ugc_url')
    specific_product = data.get('specific_product')
    client_name = data.get('client_name')
    tiktok_handle = data.get('tiktok_handle')
    acceptance_id = data.get('acceptance_id')  # optional

    try:
        # 3 seconds if not in test mode, 10 minutes if in test mode
        delay_in_seconds = 3 if (
            Environment.USE_TEST_MODE or content_type == "ugc") else 600

        post_data = {
            'ig_id': ig_id,
            'required_tagged_username': required_tagged_username,
            'ig_is_private': str(ig_is_private).lower(),
            'username': username,
            'bot_username': bot_username,
            'phone_number': phone_number,
            'offer_id': offer_id,
            'client_id': client_id,
            'location_id': location_id,
            'content_type': content_type,
            'ugc_url': ugc_url,
            'specific_product': specific_product,
            'client_name': client_name,
            'tiktok_handle': tiktok_handle
        }

        if acceptance_id:  # if acceptance_id is provided, include it in the post_data
            post_data['acceptance_id'] = acceptance_id

        res = SchedulingService.create_task(
            http_target=f"{Environment.FLASK_SERVER_URL}/verify/verify-content/",
            headers={"Authorization": API_KEY,
                     "Content-Type": "application/json"},
            http_method='POST',
            body=post_data,
            from_now_in_seconds=delay_in_seconds
        )

    except Exception as e:
        push_offer_to_manual_dash_and_send_email(f"An error has ocurred while scheduling verification: {e}", phone_number, username, offer_id, required_tagged_username,
                                                 client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, tiktok_handle)
        return jsonify({"error": str(e)}), 500

    return jsonify({}), 200


def push_offer_to_manual_dash_and_send_email(reason, phone_number, username, offer_id, required_tagged_username,
                                             client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, tiktok_handle, acceptance_id=None):
    print(f"Pushing offer to manual dashboard: {reason}")
    FirestoreService.push_offer_to_manual_dashboard(phone_number, offer_id, required_tagged_username,
                                                    client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, acceptance_id, tiktok_handle)
    with app.app_context():
        EmailService.send_manual_verification_alert(
            mail, username=username, required_tagged_username=required_tagged_username, reason=reason, ig_is_private=ig_is_private)

# Verifies that the user has tagged the required username in their story.
# Also downloads the story content to Firebase Storage if successfully verified.
# Returns id if the user has tagged the required username in their story.


@app.route('/verify/verify-content/', methods=['POST'])
def verify_content():

    try:
        data = request.json
        ig_id = data.get('ig_id')
        required_tagged_username = data.get('required_tagged_username')
        ig_is_private = data.get('ig_is_private') == "true"
        username = data.get('username')
        # only used for private verification
        bot_username = data.get('bot_username')
        phone_number = data.get('phone_number')
        offer_id = data.get('offer_id')
        client_id = data.get('client_id')
        location_id = data.get('location_id')
        content_type = data.get('content_type')
        ugc_url = data.get('ugc_url')
        specific_product = data.get('specific_product')
        client_name = data.get('client_name')
        acceptance_id = data.get('acceptance_id')  # optional
        tiktok_handle = data.get('tiktok_handle')

        # print all of the data as a map
        print("Data received:")
        print("--------------")
        print(tiktok_handle)
        print("--------------")

        matching_content = None
        content_url = None
        content_path = None
        content_metadata = None

        if content_type == "ugc":  # ugc post
            content_url = ugc_url
            content_path = FirebaseStorageService.download_image_from_url(
                ugc_url, destination_path=f"/tmp/{phone_number}_{offer_id}_{client_id}.jpg")  # download ugc from firebase storage and set content_path

        elif content_type == "instagramStory" and not ig_is_private:  # public ig story
            active_stories = public_instagram_scraper.get_stories(ig_id)
            matching_content = public_instagram_scraper.search_stories_for_tag(
                active_stories, required_tagged_username)
            if not matching_content["content_found"]:
                raise MatchingContentNotFoundException()
            if not matching_content["file_type"] == "jpg":
                raise Exception(
                    "File format is unsupported by auto-verification for Instagram stories (mp4).")
            content_url = matching_content["content"]["thumbnail_url"]
            content_path = public_instagram_scraper.download_story(
                matching_content["id"])

        elif content_type == "instagramPost" and not ig_is_private:  # public ig post
            active_posts = public_instagram_scraper.get_posts(ig_id)
            matching_content = public_instagram_scraper.search_posts_for_tag(
                active_posts, required_tagged_username)
            content_metadata = {"pk": matching_content["content"]["pk"], "caption": matching_content["content"]["caption_text"],
                                "likes": matching_content["content"]["like_count"], "comments": matching_content["content"]["comment_count"]}  # set metadata to map of post caption
            if not matching_content["content_found"]:
                raise MatchingContentNotFoundException()
            if not matching_content["file_type"] in ["jpg", "mp4"]:
                raise Exception(
                    "File format is unsupported by auto-verification for Instagram posts.")
            if matching_content["file_type"] == "jpg":
                full_content_url = matching_content["content"]["image_versions"][0]["url"]
            else:  # if the post is a video, just pass the thumbnail image to the autograder
                # TODO: test this (try a public post video)
                full_content_url = matching_content["content"]["video_versions"][0]["url"]
            content_url = matching_content["content"]["thumbnail_url"]
            # TODO: Try full test w/ post (ensure it downloads, check metadata file)
            content_path = public_instagram_scraper.download_post_or_reel(
                full_content_url)

        elif content_type == "instagramReel" and not ig_is_private:  # public ig reel
            active_reels = public_instagram_scraper.get_reels(ig_id)
            matching_content = public_instagram_scraper.search_reels_for_tag(
                active_reels, required_tagged_username)
            content_metadata = {"pk": matching_content["content"]["pk"], "caption": matching_content["content"]["caption_text"], "likes": matching_content["content"]
                                ["like_count"], "comments": matching_content["content"]["comment_count"], "views": matching_content["content"]["play_count"]}
            if not matching_content["content_found"]:
                raise MatchingContentNotFoundException()
            if not matching_content["file_type"] == "mp4":
                raise Exception(
                    "File format is unsupported by auto-verification for Instagram reels.")
            full_content_url = matching_content["content"]["video_url"]
            # just use the thumbnail to pass to autograder (in the future, we'll use the video url to pass to autograder for reels)
            content_url = matching_content["content"]["thumbnail_url"]
            # TODO: Try full test w/ reel (ensure it downloads, check metadata file)
            content_path = public_instagram_scraper.download_post_or_reel(
                full_content_url)

        else:  # unsupported content type specified
            raise Exception(
                f"Content type: {content_type} is not yet supported by auto-verification." if not ig_is_private else "Private Instagram/Tiktok verification is not yet supported by auto-verification.")

        if not content_path or not content_url:
            raise Exception(
                "An error occurred while attempting to download the content.")

        # score content
        required_tag_in_image = required_tagged_username if content_type == "instagramStory" else None
        additional_requirements = []
        # only include the specific product in requirements if it was passed in
        if specific_product and len(specific_product) > 0:
            additional_requirements.append(
                f"Include {specific_product} in the picture!")
        evaluation = ContentEvaluator.score_content(
            content_url, required_tag=required_tag_in_image, requirements=additional_requirements)
        print(evaluation)

        if not (evaluation["score"] and isinstance(evaluation["score"], int)):
            raise Exception(
                "An error occurred while attempting to evaluate the content (or while parsing the evaluation response)")

        score = evaluation["score"]

        # FOR NOW, if score is less than MINIMUM_SCORE_THRESHOLD, push to manual dashboard
        # (normally, we'd auto-reject the post, but let's wait 'til we're more confident in our prompt before we do that)
        if score < ContentEvaluator.MINIMUM_SCORE_THRESHOLD:
            if score == ContentEvaluator.TAG_NOT_FOUND_ERROR_CODE:
                raise Exception("Required tag not found in content.")
            elif score == ContentEvaluator.ADDITIONAL_REQUIREMENTS_NOT_MET_ERROR_CODE:
                raise Exception(
                    "Content did not meet additional requirements specified by the brand.")
            elif score == ContentEvaluator.PROFANITY_DETECTED_ERROR_CODE:
                raise Exception("Profanity detected in content.")
            else:
                raise Exception(
                    f"Content received a score of less than {ContentEvaluator.MINIMUM_SCORE_THRESHOLD}: ({evaluation['score']}).")

        # rename file to follow our standard naming convention
        has_metadata_flag = 1 if content_metadata else 0
        new_content_path = f"/tmp/{phone_number}_{offer_id}_{client_id}_{score}_{has_metadata_flag}_{randint(0, 999999)}.{content_path.split('.')[-1]}"
        os.rename(content_path, new_content_path)
        cloud_storage_path = f"Instagram-UGC/{client_id}/{location_id}"

        # Upload image to firebase storage if post meets minimum score threshold
        is_valid = score >= ContentEvaluator.MINIMUM_SCORE_THRESHOLD
        if is_valid:
            cloud_storage_url = FirebaseStorageService.upload_file_to_storage(
                source_path=new_content_path, destination_path=cloud_storage_path)
            # Create a document in contentMetadata collection matching image name, including caption (if necessary)
            if content_metadata:
                FirestoreService.create_content_metadata_file(file_name=new_content_path.split(
                    "/")[-1].split(".")[0], metadata=content_metadata)
                # schedule follow up to update metadata in 2, 4, 12, 24, 48, 72 hours
                schedule_metadata_updates(
                    new_content_path.split("/")[-1], ig_id)
            print(f"Uploaded content to firebase storage: {cloud_storage_url}")

        offer_approved = FirestoreService.update_final_verification(
            phone_number=phone_number, offer_id=offer_id, is_valid=is_valid, ugc_url=cloud_storage_url, content_type=content_type, score=score, acceptance_id=acceptance_id)
        if offer_approved:  # if approved, send email to team with offer details
            with app.app_context():
                EmailService.send_offer_approved_alert(mail, phone_number=phone_number, username=username, content_type=content_type, required_tagged_username=required_tagged_username,
                                                       ig_is_private=ig_is_private, client_name=client_name, specific_product=specific_product, ugc_url=cloud_storage_url, evaluation=evaluation)

    except MatchingContentNotFoundException as e:
        try:
            push_offer_to_manual_dash_and_send_email(e, phone_number, username, offer_id, required_tagged_username,
                                                     client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, tiktok_handle)
            return jsonify({"error": str(e)}), 591
        except Exception as e:
            return jsonify({"error": str(e)}), 595

    except Exception as e:
        try:
            push_offer_to_manual_dash_and_send_email(e, phone_number, username, offer_id, required_tagged_username,
                                                     client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, tiktok_handle)
            return jsonify({"error": str(e)}), 501
        except OfferNotFoundForUserException as e:
            if is_valid:  # the offer was successfully verified, but it's not in the user's acceptedOffers
                return jsonify({"error": str(e)}), 504
            else:
                return jsonify({"error": str(e)}), 505

        except Exception as e:
            return jsonify({"error": str(e)}), 500

    return jsonify({"evaluation": evaluation}), 200


def schedule_metadata_updates(file_name, pk):
    print("Scheduling metadata updates via public scraper")
    try:
        # schedule follow up to update metadata in 2, 4, 12, 24, 48, 72 hours
        for i in [2, 4, 12, 24, 48, 72]:
            SchedulingService.create_task(
                http_target=f"{Environment.FLASK_SERVER_URL}/firestore/refresh-metadata-stats/",
                headers={"Authorization": API_KEY,
                         "Content-Type": "application/json"},
                http_method='POST',
                body={"file_name": file_name, "pk": pk},
                from_now_in_seconds=3600 if not Environment.USE_TEST_MODE else 1 * i
            )
    except Exception as e:
        print(f"An error occurred while scheduling metadata updates: {e}")

    return jsonify({"success": True}), 200


@app.route("/firestore/refresh-metadata-stats/", methods=["POST"])
def refresh_metadata_stats():
    data = request.json
    file_name = data.get("file_name")
    pk = data.get("pk")
    media = public_instagram_scraper.fetch_media_by_id(pk)
    metadata = {}
    if media.get("caption"):
        metadata["caption"] = media["caption_text"]
    if media.get("like_count") and media.get("like_count") > 0:
        metadata["likes"] = media["like_count"]
    if media.get("comment_count") and media.get("comment_count") > 0:
        metadata["comments"] = media["comment_count"]
    if media.get("play_count") and media.get("play_count") > 0:
        metadata["views"] = media["play_count"]

    FirestoreService.update_metadata_stats(file_name, metadata)
    return jsonify({"success": True}), 200


# Methods related to payments

@app.route('/payment/send-payment-link', methods=['POST'])
def send_payment_link():
    data = request.json
    phone_number = data.get('phone_number')
    payment_in_cents = data.get('payment_in_cents')

    payment_service = DOTSPaymentService()
    payment_service.send_payout(phone_number=str(
        phone_number), num_cents=int(payment_in_cents))
    return jsonify({"success": True}), 200


@app.route('/payment/create-client-payment', methods=['POST'])
def create_client_payment():
    """Creates a payment intent for a client payment using Stripe."""
    data = request.json
    amount_in_usd = data.get('amount_in_usd')
    email = data.get('email')
    brand_name = data.get('brand_name')

    payment_intent = StripeService.create_payment(
        amount_in_usd, email, brand_name)
    return jsonify(client_secret=payment_intent.client_secret), 200


# 2024-03-29 Evince_dev_python
# create client payment method
@app.route('/payment/create-client-payment-method', methods=['POST'])
def create_client_payment_method():
    """Creates a payment method for a client payment using Stripe."""
    data = request.json
    email = data.get('email')
    payment_method = data.get('payment_method')

    payment_method = StripeService.create_payment_method(
        email, payment_method)
    return jsonify(payment_method=payment_method), 200


# 2024-03-29 Evince_dev_python
# update client payment method
@app.route('/payment/delete-client-payment-method', methods=['DELETE'])
def delete_client_payment_method():
    """Updates a payment method for a client payment using Stripe."""
    data = request.json
    email = data.get('email')
    payment_method = data.get('payment_method')

    payment_method = StripeService.delete_payment_method(
        email, payment_method)
    return jsonify(payment_method=payment_method), 200


# 2024-03-29 Evince_dev_python
# update client payment method
@app.route('/payment/client-payment-methods', methods=['GET'])
def get_client_payment_method():
    """get all payment method for a client payment using Stripe."""
    email_encoded = request.args.get('user')
    email = urllib.parse.unquote(email_encoded)
    # number of payment method in a request default 10
    per_page = request.args.get('limit', 100)

    payment_method = StripeService.get_payment_method(email, per_page)
    return jsonify(payment_method=payment_method), 200


# 2024-03-29 Evince_dev_python
# get client payment invoices
@app.route('/payment/client-payment-invoices', methods=['GET'])
def get_client_payment_invoices():
    """get all payment method for a client payment using Stripe."""
    email_encoded = request.args.get('user')
    email = urllib.parse.unquote(email_encoded)

    # number of payment method in a request default 10
    per_page = request.args.get('limit', 100)

    payment_invoices = StripeService.get_payment_invoices(email, per_page)
    return jsonify(payment_invoices=payment_invoices), 200


# Routes for updating Firestore
@app.route('/verify/update-final-verification/', methods=['POST'])
def update_final_verification():
    """Updates the final verification status for a user's offer."""
    data = request.json
    phone_number = data.get('phone_number')
    offer_id = data.get('offer_id')
    is_valid = data.get('story_verified', '').lower() == 'true'
    ugc_url = data.get('ugc_url')
    is_ugc_offer = data.get('is_ugc_offer', '').lower() == 'true'
    score = data.get('score')
    acceptance_id = data.get('acceptance_id')  # optional

    FirestoreService.update_final_verification(
        phone_number=phone_number,
        offer_id=offer_id,
        is_valid=is_valid,
        ugc_url=ugc_url,
        content_type=("ugc" if is_ugc_offer else "unknown"),
        score=score,
        acceptance_id=acceptance_id
    )
    return jsonify({"success": True})


@app.route('/verify/push-offer-to-manual-dashboard/', methods=['POST'])
def push_offer_to_manual_dashboard():
    data = request.json
    reason = data.get('reason')
    phone_number = data.get('phone_number')
    offer_id = data.get('offer_id')
    required_tagged_username = data.get('required_tagged_username')
    client_id = data.get('client_id')
    location_id = data.get('location_id')
    ig_is_private = data.get('ig_is_private', '').lower() == 'true'
    username = data.get('username')
    content_type = data.get('content_type')
    ugc_url = data.get('ugc_url')
    client_name = data.get('client_name')
    specific_product = data.get('specific_product')

    push_offer_to_manual_dash_and_send_email(reason, phone_number, username, offer_id, required_tagged_username,
                                             client_id, location_id, ig_is_private, content_type, ugc_url, client_name, specific_product, tiktok_handle)

    return jsonify({}), 200


@app.route('/firestore/get-detailed-client-stats/<client_id>')
def get_detailed_client_stats(client_id):
    stats = FirestoreService.get_detailed_client_stats(client_id)
    # update latest stats for client in clientStats collection
    FirestoreService.update_detailed_client_stats(client_id, stats)
    return stats

# Update latest stats for all admin accounts, clients, locations, and offers


@app.route('/firestore/update-all-stats/')
def update_all_stats():
    print("Refreshing all stats...")
    FirestoreService.refresh_and_update_all_stats()
    return {"success": True, "message": "All admin account stats were successfully updated."}, 200


# TODO: Call this endpoint from a scheduled task ->
    # when a user signs up
    # when a user accepts an offer
    # when a user's post is verified?
    # when a user redeems?
# Send an offer directly to a user's wallet
@app.route('/firestore/send-offer-to-wallet/', methods=['POST'])
def send_offer_to_wallet():
    data = request.json
    phone_number = data.get('phone_number')
    offer_id = data.get('offer_id')
    multiplier = data.get('multiplier', 1.0)

    FirestoreService.send_offer_to_wallet(
        phone_number, offer_id, multiplier=multiplier)
    return jsonify({"success": True}), 200


@app.route('/autopilot/schedule/send-targeted-offer/', methods=['POST'])
def schedule_send_targeted_offer():
    """"
    Schedules a targeted offer to be sent to a user.
    Data: 
        phone_number: The user's phone number
        event: The event that will trigger the offer to be sent
            - 'signup': The user has just signed up
                requires phone_number & client_id
            - 'acceptance': The user has accepted an offer
                requires phone_number, offer_id, & multiplier
            - 'content_verification': The user's post has been verified successfully
                requires phone_number, offer_id, & multiplier
    """
    data = request.json
    phone_number = data.get('phone_number')
    event = data.get('event')
    prev_offer_id = data.get('prev_offer_id')  # optional
    client_id = data.get('client_id')  # optional
    prev_multiplier = data.get('multiplier')  # optional
    delay_in_seconds = 15 if Environment.USE_TEST_MODE else random.randint(
        79200, 93600)  # delay between 22 and 26 hours
    SchedulingService.create_task(
        http_target=f"{Environment.FLASK_SERVER_URL}/autopilot/send-targeted-offer/",
        headers={"Authorization": Environment.FLASK_API_KEY,
                 "Content-Type": "application/json"},
        http_method='POST',
        body={"phone_number": phone_number, "event": event, "client_id": client_id,
              "prev_offer_id": prev_offer_id, "prev_multiplier": prev_multiplier},
        from_now_in_seconds=delay_in_seconds)
    return jsonify({"success": True}), 200


@app.route('/autopilot/send-targeted-offer/', methods=['POST'])
def send_targeted_offer():
    try:
        data = request.json
        phone_number = data.get('phone_number')
        event = data.get('event')
        prev_offer_id = data.get('prev_offer_id')  # optional
        client_id = data.get('client_id')  # optional
        prev_multiplier = data.get('prev_multiplier')  # optional

        Autopilot.send_targeted_offer(phone_number, event, client_id=client_id,
                                      prev_offer_id=prev_offer_id, prev_multiplier=prev_multiplier)

        return jsonify({"success": True}), 200
    except Exception as e:
        print(e)
        return jsonify({"error": str(e)}), 500

# API routes relating to exposing Firebase Storage to Dashboard

# Returns list of download links for all ugc in client folder


@app.route('/firebase-storage/get-ugc-for-client/')
def get_ugc_for_client():
    """Returns list of download links for all ugc in client folder"""
    client_id = request.args.get('client_id')
    paths = [f"Instagram-UGC/{client_id}", f"UGC-Offer-UGC/{client_id}"]
    return FirebaseStorageService.get_download_links_for_folders(paths)


# API routes for integration-related functions
@app.route('/integrations/shopify/create-price-rule/', methods=['POST'])
def create_shopify_price_rule():
    """Creates a price rule in Shopify."""
    data = request.get_json()

    # Validate incoming JSON data to ensure all required fields are present
    required_fields = ['offer_name', 'amount',
                       'discount_type', 'client_id', 'product_id']
    if not all(field in data for field in required_fields):
        return jsonify({'error': 'Missing required field(s).'}), 400

    client_id = data['client_id']
    offer_name = data['offer_name']
    amount = data['amount']
    discount_type = data['discount_type']
    product_id = data['product_id'] if data['product_id'] and data['product_id'] != "none" else None
    collection_id = data['collection_id'] if data['collection_id'] and data['collection_id'] != "none" else None
    min_purchase_amount = data['min_purchase_amount'] if data['min_purchase_amount'] else 0

    client_doc = FirestoreService.get_client_info(client_id)
    shopify_info = client_doc.get('integrations').get('shopify')
    shopify_store_name = shopify_info.get('storeName')
    shopify_access_token = shopify_info.get('accessToken')

    # Call the static method to create the price rule using the hardcoded values
    price_rule_id = ShopifyService.create_price_rule(
        shopify_store_name,
        shopify_access_token,
        offer_name,
        amount,
        discount_type,
        product_id,
        collection_id,
        min_purchase_amount
    )

    if price_rule_id:
        return jsonify({'price_rule_id': price_rule_id}), 200
    else:
        # If the price_rule_id is None, an error occurred
        return jsonify({'error': 'Failed to create price rule.'}), 500

# API routes for sending SMS messages


@app.route('/send-sms/welcome/', methods=['POST'])
def send_welcome_text():
    """Sends a welcome text to the user."""
    data = request.json
    phone_number = data.get('phone_number')
    business_name = data.get('business_name')
    business_welcome_text = data.get('business_welcome_text')
    if not phone_number:
        # Return a 400 Bad Request error
        return jsonify(error="Phone number required"), 400
    try:
        SMSService.send_welcome_text(
            phone_number, business_name, business_welcome_text)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS"), 500
    return jsonify(success=True), 200


@app.route('/send-sms/offer-acceptance/', methods=['POST'])
def send_offer_acceptance_text():
    data = request.json
    phone_number = data.get('phone_number')
    name = data.get('name', '')
    business_name = data.get('business_name')
    content_type = data.get('content_type')

    if not phone_number:
        # Return a 400 Bad Request error
        return jsonify(error="Phone number required"), 400
    if name is None:
        return jsonify(error="Name required"), 400
    if not business_name:
        return jsonify(error="Business name required"), 400
    try:
        SMSService.send_offer_acceptance_text(
            phone_number, name, business_name, content_type)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS"), 500
    return jsonify(success=True), 200


@app.route('/send-sms/accept-instagram-follow-request-text/', methods=['POST'])
def send_accept_instagram_follow_request_text():
    data = request.json
    phone_number = data.get('phone_number')
    bot_username = data.get('bot_username')
    if not phone_number:
        # Return a 400 Bad Request error
        return jsonify(error="Phone number required"), 400
    try:
        SMSService.send_accept_instagram_follow_request_text(
            phone_number, bot_username)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS"), 500
    return jsonify(success=True), 200


@app.route('/send-sms/credit-reminder/', methods=['POST'])
def send_credit_reminder_text():
    data = request.json
    phone_number = data.get('phone_number')
    business_name = data.get('business_name')
    compensation = data.get('compensation')
    credit_type = data.get('credit_type')
    offer_id = data.get('offer_id')
    whitelabel_url = data.get('whitelabel_url')

    if not phone_number or not business_name or not compensation or not credit_type or not offer_id:
        return jsonify(error="Missing required parameters"), 400

    # Ensure credit has not already been redeemed

    user_file = FirestoreService.get_user_file(phone_number).to_dict()
    for accepted_offer in user_file["acceptedOffers"]:

        for accepted_offer in user_file["acceptedOffers"]:
            if accepted_offer["offerID"] == offer_id:
                if accepted_offer["isRedeemed"]:
                    return jsonify(error="Credit has already been redeemed"), 201
                else:
                    try:
                        return SMSService.send_credit_reminder_text(phone_number, business_name, compensation, credit_type, whitelabel_url=whitelabel_url)
                    except Exception as e:
                        print(e)
                        # Return a 500 Internal Server Error to the client
                        return jsonify(error="An error occurred while sending the SMS"), 501

    return jsonify(error="The offer for the specified offer ID was not found for the user"), 500


@app.route('/send-sms/private-offer-alert/', methods=['POST'])
def send_private_offer_alert_text():
    data = request.json
    phone_number = data.get('phone_number')
    business_name = data.get('business_name')
    client_id = data.get('client_id')
    client_ig_handle = data.get('client_ig_handle')
    content_type = data.get('content_type')
    credit_type = data.get('credit_type')
    compensation = data.get('compensation')
    min_compensation = data.get('min_compensation')
    max_compensation = data.get('max_compensation')
    whitelabel_url = data.get('whitelabel_url')
    hard_cash = data.get('hard_cash') == 'true'

    if not phone_number:
        # Return a 400 Bad Request error
        return jsonify(error="Phone number required"), 400
    if not business_name:
        return jsonify(error="Business name required"), 400
    if not client_id:
        return jsonify(error="Client ID required"), 400
    if not client_ig_handle:
        return jsonify(error="Client Instagram handle required"), 400
    if not content_type:
        return jsonify(error="Content type required"), 400
    if not credit_type:
        return jsonify(error="Credit type required"), 400
    try:
        SMSService.send_private_offer_alert_text(phone_number, business_name, client_ig_handle=client_ig_handle, content_type=content_type, credit_type=credit_type,
                                                 compensation=compensation, min_compensation=min_compensation, max_compensation=max_compensation, whitelabel_url=whitelabel_url, hard_cash=hard_cash)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS"), 500
    return jsonify(success=True), 200

# send post reminder: if a user accepts an offer but doesn't post


@app.route('/send-sms/send-post-reminder/', methods=['POST'])
def send_post_reminder_text():
    data = request.json
    phone_number = data.get('phone_number')
    client_instagram_handle = data.get('client_instagram_handle')
    content_type = data.get('content_type')
    credit_type = data.get('credit_type')
    compensation = data.get('compensation')
    min_compensation = data.get('min_compensation')
    max_compensation = data.get('max_compensation')
    hard_cash = data.get('hard_cash') == 'true'

    try:
        SMSService.send_post_reminder_text(phone_number, client_instagram_handle, content_type,
                                           credit_type, compensation, min_compensation, max_compensation, hard_cash)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS: send_post_reminder"), 500
    return jsonify(success=True), 200

# send post resubmission: if a user posts a picture but it's missing a requirement


@app.route('/send-sms/send-post-resubmission/', methods=['POST'])
def send_post_resibmission():
    data = request.json
    phone_number = data.get('phone_number')
    missing_requirement_error_code = data.get('missing_requirement_error_code')
    content_type = data.get('content_type')
    client_instagram_handle = data.get('client_instagram_handle')
    specific_product = data.get('specific_product')
    try:
        SMSService.send_post_resubmission(
            phone_number, missing_requirement_error_code, content_type, client_instagram_handle, specific_product)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the SMS: send_post_reminder"), 500
    return jsonify(success=True), 200


# API routes for sending emails
@app.route('/send-internal-email/schedule/story-verification-reminder/', methods=['POST'])
def schedule_story_verification_reminder():
    data = request.json
    phone_number = data.get('phone_number')
    verification_email = data.get('verification_email')
    verification_username = data.get('verification_username')
    username = data.get('username')
    required_tagged_username = data.get('required_tagged_username')
    try:
        # Schedule verifcation using SchedulingService
        delay_in_seconds = 18000
        res = SchedulingService.create_task(
            http_target=f"{Environment.FLASK_SERVER_URL}/send-internal-email/story-verification-reminder/",
            headers={"Authorization": API_KEY,
                     "Content-Type": "application/json"},
            body=json.dumps({
                "phone_number": phone_number,
                "verification_email": verification_email,
                "verification_username": verification_username,
                "username": username,
                "required_tagged_username": required_tagged_username
            }),
            http_method='POST',
            from_now_in_seconds=delay_in_seconds)
    except Exception as e:
        print("Error scheduling task: " + str(e))
        return jsonify(success=False, error=str(e)), 500
    return jsonify(success=True), 200


@app.route('/send-internal-email/story-verification-reminder/', methods=['POST'])
def send_story_verification_reminder():
    data = request.json
    phone_number = data.get('phone_number')
    verification_email = data.get('verification_email')
    verification_username = data.get('verification_username')
    username = data.get('username')
    required_tagged_username = data.get('required_tagged_username')

    if not phone_number or not verification_email or not verification_username or not username or not required_tagged_username:
        return jsonify(error="Missing required parameters"), 400

    try:
        EmailService.send_manual_verification_reminder(
            mail, verification_email, verification_username, username, required_tagged_username)
    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the email"), 500
    return jsonify(success=True), 200

# Admin Dashboard endpoints


@app.route('/admin-dashboard/create-client-dashboard-admin/', methods=['POST'])
def create_client_dashboard_admin_account():
    data = request.json
    print(data)
    email = data.get('email')
    password = data.get('password')
    account_name = data.get('account_name')
    try:
        FirestoreService.create_dashboard_admin_auth_and_file(
            email, password, account_name)

    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the email"), 500

    return jsonify(success=True), 200


@app.route('/dashboard/add-additional-seat/', methods=['POST'])
def add_additional_seat():
    data = request.json
    print(data)
    email = data.get('email')
    password = data.get('password')
    full_name = data.get('full_name')
    admin_id = data.get('admin_id')

    try:
        FirestoreService.add_additional_seat(
            email, password, full_name, admin_id)

    except Exception as e:
        print(e)
        # Return a 500 Internal Server Error to the client
        return jsonify(error="An error occurred while sending the email"), 500

    return jsonify(success=True), 200


# Image proxy to bypass CORS restrictions
@app.route('/load-image/')
def get_image():
    url = request.args.get('url')
    response = requests.get(url)  # make a request to the image URL
    return send_file(BytesIO(response.content), mimetype='image/jpeg')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9001, debug=False)  # Start the Flask application
def application(environ, start_response):
    status = '200 OK'
    output = b'Hello Howtoforge!\n'
    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output] 
