# coding: UTF-8
from flask import Response, Flask, request, render_template, send_file, redirect, url_for
import time
from flask_httpauth import HTTPBasicAuth
import pandas as pd
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import openai
import csv
import json
from io import StringIO, BytesIO
import logging
from urllib.parse import urlparse, parse_qs
from dotenv import load_dotenv
import os

# Load environment variables from .env file
load_dotenv()
BASE_URL = os.getenv('BASE_URL')

# Global variables for progress tracking
total_urls = 0
processed_urls = 0

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__, static_url_path='/ai-form-bot/static')
app.config['APPLICATION_ROOT'] = '/ai-form-bot'
auth = HTTPBasicAuth()

# Set OpenAI API key from environment variable
openai.api_key = os.getenv('OPENAI_API_KEY')

users = {
    "admin": "secret"
}

@auth.verify_password
def verify_password(username, password):
    if username in users and users[username] == password:
        return username
    else:
        logger.warning(f"Failed authentication for user: {username}")
        return None

@app.route('/ai-form-bot/favicon.ico')
def favicon():
    return '', 204  # No Content

@app.route('/ai-form-bot/progress')
def progress():
    def generate():
        global total_urls, processed_urls
        while processed_urls < total_urls:
            yield f"data: {json.dumps({'total': total_urls, 'processed': processed_urls})}\n\n"
            time.sleep(1)
    return Response(generate(), mimetype='text/event-stream')

@app.route('/ai-form-bot/', methods=['GET', 'POST'])
@auth.login_required
def upload_file():
    global total_urls, processed_urls
    if request.method == 'POST':
        file = request.files['file']
        if file and file.filename:
            # Reset progress
            total_urls = 0
            processed_urls = 0

            df = pd.read_csv(file)
            urls = df['URL'].tolist()
            user_info = {
                'company_name': request.form.get('company_name'),
                'full_name': request.form.get('full_name'),
                'kana': request.form.get('kana'),
                'email': request.form.get('email'),
                'phone_number': request.form.get('phone_number'),
                'address': request.form.get('address'),
                'postal_code': request.form.get('postal_code'),
                'department': request.form.get('department'),
                'position': request.form.get('position'),
                'site_url': request.form.get('site_url'),
                'message': request.form.get('message')
            }
            report = process_urls(urls, user_info)
            return send_file(report, as_attachment=True, download_name='processing_report.csv', mimetype='text/csv')
        else:
            return "No file selected or file is empty."
    return render_template('upload.html')

@app.route('/ai-form-bot/logout')
@auth.login_required
def logout():
    return redirect(url_for('upload_file'))

def process_urls(urls, user_info):
    global total_urls, processed_urls
    total_urls = len(urls)
    processed_urls = 0

    session = requests.Session()
    report = StringIO()
    csv_writer = csv.writer(report)
    csv_writer.writerow([
        'Main URL', 
        'URL Access', 
        'Links Found',
        'Form URL',
        'Form Fields Found', 
        # 'Form Mapping', 
        # 'Form Submission',
        'Submitted Form Data',
        'Submission Verification',
        'Error Details'
    ])

    for main_url in urls:
        row = [main_url]
        try:
            # Step 1: Main URL Access
            response = session.get(main_url)
            response.raise_for_status()
            row.append('Success')

            # Step 2: Get all links
            all_links = get_all_links(main_url)
            row.append(f'Found {len(all_links)} links')

            form_submitted = False
            for url in all_links + [main_url]:
                try:
                    # Step 3: Find Form Fields
                    response = session.get(url)
                    soup = BeautifulSoup(response.text, 'html.parser')
                    fields = find_form_fields(soup)

                    if fields:
                        # Step 4: Form Mapping
                        form_data = generate_form_mapping(fields, user_info)

                        # Step 5: Form Submission
                        submission_result, submission_verification = find_and_submit_form(session, url, form_data)
                        if submission_result:
                            row.extend([
                                url,
                                'Success',
                                # json.dumps(fields, ensure_ascii=False),
                                # json.dumps(form_data, ensure_ascii=False),
                                'Success',
                                json.dumps(form_data, ensure_ascii=False),
                                submission_verification,
                                ''
                            ])
                            form_submitted = True
                            break
                except Exception as e:
                    logger.error(f"Error processing URL {url}: {str(e)}")
                    continue

            if not form_submitted:
                row.extend(['N/A', 'Failure - No suitable form found', '', '', '', '', 'N/A', 'No form submitted'])

        except requests.RequestException as e:
            row.extend([f'Failure - {str(e)}', '', '', '', '', '', '', '', str(e)])
        
        csv_writer.writerow(row)
        processed_urls += 1
        update_progress(processed_urls, total_urls)

    report_content = report.getvalue().encode('utf-8')
    report_bytes = BytesIO(report_content)
    report_bytes.seek(0)
    return report_bytes

def find_form_fields(soup):
    fields = []
    for form in soup.find_all('form'):
        for element in form.find_all(['input', 'textarea', 'select']):
            if element.name == 'input':
                input_type = element.get('type', 'text')
                if input_type in ['text', 'email', 'tel', 'checkbox', 'radio', 'hidden']:
                    fields.append(str(element))
            else:
                fields.append(str(element))
    return fields

def get_all_links(url):
    domain = urlparse(url).netloc
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    links = [a.get('href') for a in soup.find_all('a', href=True)]
    full_links = []
    for link in links:
        full_link = urljoin(url, link)
        link_domain = urlparse(full_link).netloc
        if link_domain == domain or "forms.gle" in link_domain or "docs.google.com" in link_domain:
            full_links.append(full_link)
    return full_links

def generate_form_mapping(fields, user_info):
    prompt = f"""
    Given the following form fields and user information, identify the corresponding input names in the form and map them to the provided values. Handle checkboxes, radio buttons, and select fields appropriately. Fill all inputs and select the most appropriate option in checkboxes or radio buttons.
    
    Form Fields:
    {fields}
    
    User Information:
    会社名: {user_info['company_name']}
    名前（姓名）: {user_info['full_name']}
    ふりがな: {user_info['kana']}
    フリガナ: {user_info['kana']}
    メールアドレス: {user_info['email']}
    電話番号: {user_info['phone_number']}
    住所: {user_info['address']}
    郵便番号: {user_info['postal_code']}
    部署名: {user_info['department']}
    役職: {user_info['position']}
    サイトURL: {user_info['site_url']}
    メッセージ: {user_info['message']}

    For checkboxes and radio buttons, set the value to "true" for the closest option to the user information, otherwise "false".
    For select fields, choose the most appropriate option based on the user information.
    """
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "You are a sales representative. Please respond with a JSON object mapping form field names to user information values. For checkboxes and radio buttons, use boolean values. For select fields, provide the value of the most appropriate option."},
            {"role": "user", "content": prompt}
        ],
        max_tokens=500
    )
    
    form_mapping = json.loads(response['choices'][0]['message']['content'])
    return form_mapping

def find_and_submit_form(session, url, form_data):
    response = session.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    forms = soup.find_all('form')
    logger.info(f"forms founds: {forms}")
    for form in forms:
        form_action = form.get('action')
        form_method = form.get('method', 'get').lower()
        form_inputs = form.find_all(['input', 'textarea', 'select'])
        
        payload = {}
        for element in form_inputs:
            element_name = element.get('name')
            element_type = element.get('type', '').lower() if element.name == 'input' else ''
            if element_name:
                if element_type == 'checkbox' or element_type == 'radio':
                    if form_data.get(element_name) == True:
                        payload[element_name] = element.get('value', 'on')
                elif element.name == 'select':
                    options = element.find_all('option')
                    for option in options:
                        if option.get('value') == form_data.get(element_name):
                            payload[element_name] = option.get('value')
                            break
                else:
                    payload[element_name] = form_data.get(element_name, '')

        try:
            submit_url = urljoin(url, form_action)
            
            # Instead of submitting, we'll log the action and return a mock response
            logger.info(f"Would submit form to {submit_url} with method {form_method.upper()} and payload: {payload}")
            
            # Create a mock response for testing
            class MockResponse:
                def __init__(self):
                    self.status_code = 200
                    self.text = "<html><body>Thank you for your submission</body></html>"
                    self.url = submit_url

                def raise_for_status(self):
                    pass

            submit_response = MockResponse()
            
            # Verify submission (this will now always indicate success due to our mock response)
            verification_result = verify_submission(submit_response)
            return True, verification_result, submit_url, form_method.upper()
        except Exception as e:
            logger.error(f"Form processing failed: {str(e)}")
            continue
    return False, "No form submitted"

def verify_submission(response):
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # Check for common success indicators
    success_keywords = ['thank you', 'success', 'submitted', 'received']
    page_text = soup.get_text().lower()
    
    for keyword in success_keywords:
        if keyword in page_text:
            return f"Submission likely successful. Found '{keyword}' on the response page."
    
    # Check for form absence
    if not soup.find('form'):
        return "Form no longer present on the page. Submission might be successful."
    
    # Check URL parameters for success indicators
    url_params = parse_qs(urlparse(response.url).query)
    if 'success' in url_params or 'submitted' in url_params:
        return "URL parameters indicate successful submission."
    
    return "Unable to verify submission success. Please check manually."

def update_progress(processed, total):
    global total_urls, processed_urls
    total_urls = total
    processed_urls = processed

def get_total_urls():
    global total_urls
    return total_urls

def get_processed_urls():
    global processed_urls
    return processed_urls

if __name__ == '__main__':
    app.run(debug=True)
